#1,214 – Naming Scheme for XAML Elements

Although XAML elements do not require a name, it’s sometimes useful to name them for debugging purposes–e.g. when using Visual Studio’s Live Visual Tree.

Below is a modest proposal for a naming convention for various WPF controls.

  • AccessText – at
  • Border – brd
  • BulletDecorator – bd
  • Button – btn
  • Calendar – cal
  • Canvas – cnv
  • CheckBox – chk
  • ComboBox – cbo
  • ContextMenu – ctx
  • DataGrid – dg
  • DatePicker – dat
  • DockPanel – dp
  • Expander – exp
  • Frame – fr
  • Grid – grd
  • GridSplitter – gsp
  • GroupBox – grp
  • Hyperlink – hyp
  • Image – img
  • InkCanvas – ikc
  • InkPresenter – ikp
  • Label – lbl
  • ListBox – lb
  • ListView – lv
  • MediaElement – me
  • Menu – mnu
  • NavigationWindow – nw
  • Page – pg
  • Panel – pnl
  • PasswordBox pwd
  • Popup – pop
  • ProgressBar – pb
  • RadioButton rdo
  • ResizeGrip – rgr
  • RepeatButton rpt
  • RichTextBox – rtb
  • ScrollBar – sb
  • ScrollViewer – sv
  • Separator – sep
  • Slider – sli
  • StackPanel – sp
  • StatusBar – stb
  • TabControl – tab
  • TabItem – tbi
  • TextBlock – tb
  • TextBox – txt
  • Thumb – th
  • ToolBar – tbr
  • ToolTip – tt
  • TreeView – tv
  • Viewbox – vb
  • VirtualizingStackPanel – vsp
  • Window – win
  • WrapPanel – wp

You could certainly go too far in naming controls in a WPF application. Instead of naming every single control, it’s probably more sensible to name a subset of controls, providing names when it makes sense.

#1,213 – Why You May Want to Name XAML Elements

In the days of Win Forms, we had to name every user interface element because the name is how we referenced the element when setting initial properties and then working with the element from code-behind.

In WPF, most developers have (hopefully) trained themselves to not bother with naming elements. Ideally, all interaction with a control is done through the use of commands and data binding, which means that there is then no need to ever access a control from code-behind.

Having said that, there is one valid use case for naming XAML elements in WPF. When you use a debugging tool that shows you the visual tree of an application, it’s helpful to have your elements named, so you can figure out what’s what.

Below is a XAML fragment for a simple WPF application. Note that I’ve named some of the elements (I’m not bothering to name simple labels).

    <Grid x:Name="grdMain" Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Button x:Name="btnPressMe" Grid.Row="0" Grid.Column="0" Margin="10" Command="local:SomeViewModel.PressMeCommand" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}" Padding="10,5"/>
        <TextBlock x:Name="txbPressResults" Grid.Row="0" Grid.Column="1" Margin="10" Text="{Binding PressResults}"/>

        <TextBlock Grid.Row="1" Grid.Column="0" Text="Say something:"/>
        <TextBox x:Name="txtYourText" Grid.Row="1" Grid.Column="1" Text="{Binding YourText}"/>

        <TextBlock Grid.Row="2" Grid.ColumnSpan="2" Text="Gosh, I love this application"/>
    </Grid>

When I run the application, I can bring up Visual Studio’s Live Visual Tree and then explore the visual tree of the application. Notice the named elements in the visual tree, corresponding to the names given in the XAML.

Naming elements in this way can make debugging a bit easier when you’re navigating through the visual tree.

#1,212 – Viewing WPF Trace Output Outside of Visual Studio

When you’re running a WPF application from within Visual Studio, you can view trace output in Visual Studio’s Output window. That is, you’ll see any trace output that you generate using Trace.WriteLine. This doesn’t work, however, if you’re not running in Debug mode or when you run your application outside of Visual Studio.

There’s a tool that you can use, however, to capture Trace output for a WPF application, even if it it’s a Release build and is running outside of Visual Studio.

The DebugView tool, available for download here, will display debug output for all applications in Windows. This includes .NET Trace output, which means that the application will display all trace output while your application is running.

Note that DebugView shows debug output for all applications, which means that you may need to filter out applications that you don’t care about. (See OutputDebugString call in the Win32 library).

Let’s say that we do the following in a Button_Click event:

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Trace.WriteLine($"You clicked a button at {DateTime.Now.ToLongTimeString()}");
        }

We can now build and run the WPF application (i.e. after shutting down Visual Studio). Running DebugView, you can see the output.

#1,211 – Catching Exceptions Originating in Property Accessors

Post #1,210 explained that when data binding causes a property accessor to fire (either get or set) and an exception occurs, the exception will be ignored by the data binding layer. The exception gets caught internally and converted into a binding error that you normally don’t see.

We can use the technique described in #1,209 to to intercept this binding error and convert it back to an exception. This avoids the problem of these original exceptions never being seen.

Below is a complete example, setting us up with a NullReferenceException that comes out of a property set accessor. We wire up a trace listener that will catch this error and other binding errors.

First, we define a BindingErrorTraceListener class, which intercepts the binding errors by overriding the WriteLine method. In the snippet below, we simply throw a new exception that contains the entire text of the binding error. This will work for all binding errors (e.g. due to binding expression problems or due to exceptions coming out of property accessors).

    public class BindingErrorTraceListener : TraceListener
    {
        public override void Write(string s) { }

        public override void WriteLine(string message)
        {
            throw new Exception(message);
        }
    }

Next, we wire up the listener in our application’s startup logic. We also set up a handler for unhandled exceptions and display the body of the exception. (You could just as easily log the exception here).

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            PresentationTraceSources.Refresh();
            PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error;
            PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingErrorTraceListener());

            DispatcherUnhandledException += App_DispatcherUnhandledException;
        }

        private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.Message);
        }
    }

For existing WPF applications, this is all you need to do. All binding errors will now be converted to exceptions, caught and displayed. Some might argue that this should be standard fare for every WPF application. (Maybe not displaying the errors to the user, but at least logging them).

The snippets below are for a sample application, so that you can see this in action.

We start with a window that lets the user type in someone’s name then then displays the number of characters in the name.

<Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" Title="A ColorAnimation" Height="350" Width="525">
    
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        
        <TextBlock Text="Enter text:"/>
        <TextBox Grid.Column="1" Margin="10,0" Text="{Binding YourTextqqqq, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBlock Grid.Row="1" Margin="0,10" Text="Length:"/>
        <TextBlock Grid.Row="1" Grid.Column="1" Margin="0,10" Text="{Binding TextLength}"/>
    </Grid>
</Window>

In the code-behind, we simply wire up the DataContext of the window to a viewmodel.

    public partial class MainWindow : Window
    {
        public SomeViewModel ViewModel { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            ViewModel = new SomeViewModel();
            this.DataContext = ViewModel;
        }
    }

Finally, we have the body of our viewmodel, where we make an attempt to call a method on a BobNotify object when the user types “Bob”. We haven’t initialized the object, so this will generate a null reference exception.

    public class SomeViewModel : INotifyPropertyChanged
    {
        private BobNotify _bobNotify;

        private string _yourText;
        public string YourText
        {
            get { return _yourText; }
            set
            {
                if (SetProp(ref _yourText, value))
                {
                    // E-mail Bob if someone types his name
                    // (but we forgot to initialize BobNotify object, so will get NullRefException here).
                    if (_yourText == "Bob")
                        _bobNotify.SendEmail(_yourText);

                    RaisePropertyChanged("TextLength");
                }
            }
        }

        public int TextLength
        {
            get
            {
                return string.IsNullOrWhiteSpace(_yourText) ? 0 : _yourText.Length;
            }
        }

        protected bool SetProp<T>(ref T backingField, T value, [CallerMemberName] string propName = null)
        {
            bool valueChanged = false;

            // Can't use equality operator on generic types
            if (!EqualityComparer<T>.Default.Equals(backingField, value))
            {
                backingField = value;
                RaisePropertyChanged(propName);
                valueChanged = true;
            }

            return valueChanged;
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropertyChanged(string propname)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propname));
        }
    }

When we put all of these pieces together and test the application, we see that when the user types “Bob”, we get the dialog popping up with the full text of the binding error. In the body of the error you can see the original NullReferenceException.

One interesting thing to note is the part saying target element is ‘TextBox’ (Name=”). The name is empty because in .xaml, we didn’t name the element. You often avoid naming XAML elements in WPF because you shouldn’t need to interact with the elements in your code-behind. However, naming elements can be useful in cases like this, where the name would normally be reported.

#1,210 – Exceptions in Property Accessors Can Be Ignored in Production Code

In the same way that binding errors are quietly swallowed in production code, exceptions originating in property getters or setters invoked as a result of WPF data binding can also be quietly ignored in production code.

Assume that we bind a TextBox.Text property to a string-based property in a ViewModel, as below. Note that when the data binding engine tries to set a property value of “Bob”, we’ll get a NullReferenceException.

        private BobNotify _bobNotify;

        private string _yourText;
        public string YourText
        {
            get { return _yourText; }
            set
            {
                if (SetProp(ref _yourText, value))
                {
                    // E-mail Bob if someone types his name
                    // (but we forgot to initialize BobNotify object, so will get NullRefException here).
                    if (_yourText == "Bob")
                        _bobNotify.SendEmail(_yourText);

                    RaisePropertyChanged("TextLength");
                }
            }
        }

        public int TextLength
        {
            get
            {
                return string.IsNullOrWhiteSpace(_yourText) ? 0 : _yourText.Length;
            }
        }

If we include this code in a release build and do nothing special to listen for binding errors, the exception will be quietly swallowed. The only hint that something went wrong is that the TextBlock that we bind TextLength to doesn’t get updated once we type the second “b” in “Bob”.

We can handle these sorts of errors in the same way that we did for other types of binding errors, by adding a binding error trace listener.

 

#1,209 – Catching Data Binding Errors Part 2

In Part 1, I described how to use a TraceSource to intercept data binding errors. Below, we convert these binding errors into exceptions. You then can know that the error will get reported at runtime and you can catch and handle the exception as you like.

(Code below is inspired by WpfBindingErrors project and Jason Bock’s blog post).

Building on the code in the earlier post, we modify the WriteLine method to parse the resulting error message and build up a custom exception type.

    public class BindingErrorException : Exception
    {
        public string SourceObject { get; set; }
        public string SourceProperty { get; set; }
        public string TargetElement { get; set; }
        public string TargetProperty { get; set; }

        public BindingErrorException() 
            : base() { }

        public BindingErrorException(string message)
            : base(message) { }

    }

    public class BindingErrorTraceListener : TraceListener
    {
        private const string BindingErrorPattern = @"^BindingExpression path error(?:.+)'(.+)' property not found(?:.+)object[\s']+(.+?)'(?:.+)target element is '(.+?)'(?:.+)target property is '(.+?)'(?:.+)$";

        public override void Write(string s) { }

        public override void WriteLine(string message)
        {
            var xx = new BindingErrorException(message);

            var match = Regex.Match(message, BindingErrorPattern);
            if (match.Success)
            {
                xx.SourceObject = match.Groups[2].ToString();
                xx.SourceProperty = match.Groups[1].ToString();
                xx.TargetElement = match.Groups[3].ToString();
                xx.TargetProperty = match.Groups[4].ToString();
            }

            throw xx;
        }
    }

As before, we attach a listener at startup. We also catch unhandled binding exceptions and display a MessageBox.

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            PresentationTraceSources.Refresh();
            PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error;
            PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingErrorTraceListener());

            DispatcherUnhandledException += App_DispatcherUnhandledException;
        }

        private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            var bex = e.Exception as BindingErrorException;
            if (bex != null)
            {
                MessageBox.Show($"Binding error. {bex.SourceObject}.{bex.SourceProperty} => {bex.TargetElement}.{bex.TargetProperty}");
            }
        }
    }

For a bad property name that leads to a binding error, we then get a nice little error.

 

#1,208 – Catching Data Binding Errors Part 1

In WPF, data binding errors by default are quietly swallowed, rather than throwing an exception.

Happily, there is a TraceSource that we can use to intercept all binding errors. All data binding errors will go through this trace source and we can therefore add a TraceListener to the trace source’s Listeners collection in order to intercept the error.

We start by creating a simple class deriving from TraceListener that overrides Write and WriteLine methods. These methods will be invoked when messages come from the trace source. Note that we don’t yet do anything useful with these messages, but just dump them to standard trace output (to prove to ourselves that we got them).

   public class BindingErrorTraceListener : TraceListener
    {
        public override void Write(string message)
        {
            Trace.WriteLine(string.Format("==[Write]{0}==", message));
        }

        public override void WriteLine(string message)
        {
            Trace.WriteLine(string.Format("==[WriteLine]{0}==", message));
        }
    }
}

We can now wire our listener into the standard data binding trace source. Below, we do this at application startup.


    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error;
            PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingErrorTraceListener());
        }
    }

At this point, we’re not doing anything with the binding errors. But if you watch the output window, you’ll see that we’re now capturing them.

Next time, we’ll look at converting these errors into exceptions that you can catch.