#1,205 – Use CallerMemberName Attribute to Make INotifyPropertyChanged Implementation Cleaner

The INotifyPropertyChanged interface is central to using data binding in WPF. You typically create ViewModels containing properties that fire a PropertyChanged event whenever a property value changes. Implementing this plumbing over and over for every property can become tedious. This argues for a reusable pattern to make the per-property code cleaner.

Specifying string-based property names when raising the PropertyChanged event can also be error-prone. When, passing property names as string literals, a misspelled property name doesn’t lead to a compiler warning, but just a quiet data binding failure.

Below is a pattern you can use to make property change code cleaner. It relies on the CallerMemberName attribute, which can be used to default a method parameter to the name of a caller–the property name in this case.

We have a generic method that compares a new property value to the current value in the backing variable. If the value has changed, it assigns the new value and fires the property changed event.

        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 { };

        protected void RaisePropertyChanged(string propName)
        {
            if (!string.IsNullOrWhiteSpace(propName) && (PropertyChanged != null))
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

A standard property implementation can now look pretty clean. (Note: We’re not checking the return value of SetProp, but we could do that if we wanted to perform other logic when the property value changes).

        private Dog _selectedDog;
        public Dog SelectedDog
        {
            get { return _selectedDog; }
            set { SetProp(ref _selectedDog, value); }
        }

You would generally put this sort of code in a common base class that all of your ViewModel classes could inherit from.

#1,204 – Using a DataTrigger to Change Content in a ContentPresenter

You can set the ContentTemplate property of a ContentPresenter to a panel containing some content, using a DataTemplate.

This technique becomes even more useful when you have different types of content to display, depending on a particular state in your application. In the example below, we set up a Style for a ContentPresenter that sets default content for the ContentPresenter and then swaps in entirely different content when the JobDone property in the data context becomes true.

    <Window.Resources>
        <DataTemplate x:Key="DefaultContent">
            <StackPanel>
                <TextBlock Margin="10" Text="Some default content here.."/>
                <TextBlock Margin="10" Text="Maybe show progress for operation"/>
            </StackPanel>
        </DataTemplate>

        <DataTemplate x:Key="AllDoneContent">
            <StackPanel>
                <TextBlock Margin="10" Text="** This is the ALL DONE content..."
                           Foreground="Green"/>
                <TextBlock Margin="10" Text="Put anything you like here"/>
                <Button Margin="10" Content="Click Me" HorizontalAlignment="Left"/>
            </StackPanel>
        </DataTemplate>

        <Style x:Key="MyContentStyle" TargetType="ContentPresenter">
            <Setter Property="ContentTemplate" Value="{StaticResource DefaultContent}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding JobDone}" Value="True">
                    <Setter Property="ContentTemplate" Value="{StaticResource AllDoneContent}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
        
    </Window.Resources>
    
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <ContentPresenter Grid.Row="0" Style="{StaticResource MyContentStyle}" Content="{Binding}"/>
        
        <Separator Grid.Row="1"/>

        <CheckBox Grid.Row="2" Margin="10" Content="Mark job done" IsChecked="{Binding JobDone}"/>
    </Grid>

Here’s how the application looks in the two states. Note that we can toggle between the two states using the CheckBox.

#1,203 – Create a Reusable Group of Elements with a ContentPresenter

There are several ways to achieve reuse in WPF. You can create a reusable control by creating shared data and control templates for a single type of control. You can also create custom controls, providing custom code and layout.

One simple way to reuse a group of controls is by using a ContentPresenter with a reusable ContentTemplate.

In the example below, we have a small grid displaying a person’s name and address. To use this set of controls in multiple places in an application, we place them in a DataTemplate and then use a ContentPresenter wherever we want the set of controls to appear.

The DataTemplate is defined in the resources section for a window. The main body of the Window includes two instances of the set of controls. Note that we need to set the Content of each ContentPresenter to the bound data context of the window. Not shown here, but assumed, is that our Window is bound to an object having MyName and Address properties.

    <Window.Resources>
        <DataTemplate x:Key="MyGridContentTemplate">
            <Grid Margin="8">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>

                <TextBlock Text="Your name is:"/>
                <TextBlock Grid.Column="1" Margin="8,0,0,0"
                           FontWeight="Bold"
                           Text="{Binding MyName}"/>

                <TextBlock Grid.Row="1" Text="Your address is:"/>
                <TextBlock Grid.Row="1" Grid.Column="1" Margin="8,0,0,0"
                           FontWeight="Bold"
                           Text="{Binding Address}"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <ContentPresenter Grid.Row="0" ContentTemplate="{StaticResource MyGridContentTemplate}" Content="{Binding}"/>
        
        <Separator Grid.Row="1"/>

        <ContentPresenter Grid.Row="2" ContentTemplate="{StaticResource MyGridContentTemplate}" Content="{Binding}"/>
    </Grid>

Here’s what the application looks like at run-time:

#1,202 – Using a Color Animation to Draw Emphasis to Something

There are times when you might want to draw a user’s attention to some user interface element, for example when some event causes the contents of the element to change. A ColorAnimation on the Background of the element is a nice way to do that.

Below, we have a TextBlock that binds to a string property and a Button that changes that property’s value. We set up a style for the TextBlock containing an EventTrigger that fires whenever the target of the binding changes, i.e. the trigger will fire whenever the value of the Text property changes.

In the trigger, we have a Storyboard continuing two animations that run consecutively. The first fades in the background color and the second fades back to the original transparent value. The first animation is shorter, so that we have a longer fade out.

Here’s the XAML fragement:

<Window.Resources>
    <ResourceDictionary>
        <Style x:Key="LookAtMe" TargetType="TextBlock">
            <Setter Property="Background" Value="Transparent"/>
            <Style.Triggers>
                <EventTrigger RoutedEvent="Binding.TargetUpdated">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)" 
                                                From="Transparent" To="Magenta" FillBehavior="Stop" 
                                                BeginTime="0:0:0" Duration="0:0:0.3"/>
                                <ColorAnimation Storyboard.TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)" 
                                                From="Magenta" To="Transparent" 
                                                BeginTime="0:0:0.3" Duration="0:0:1"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</Window.Resources>
    
    <StackPanel Margin="10">
        <TextBlock Text="{Binding SomeText, NotifyOnTargetUpdated=True}" 
                   Style="{StaticResource LookAtMe}"/>
        <Button Content="Do Something" 
                Margin="0,10,0,0" HorizontalAlignment="Center" 
                Click="btnDoSomething_Click"/>
    </StackPanel>

In the code-behind, we have the SomeText property and code to change this property whenever the button is pressed.

private string _someText = "Original text";
public string SomeText
{
    get { return _someText; }
    set
    {
        if (value != _someText)
        {
            _someText = value;
            RaisePropChanged("SomeText");
        }
    }
}

private int nextNum = 1;
private void btnDoSomething_Click(object sender, RoutedEventArgs e)
{
    SomeText = string.Format("Change to {0}", nextNum++);
}

public event PropertyChangedEventHandler PropertyChanged = delegate { };

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

When you run this code, the background of the TextBlock flashes magenta whenever you click on the button.

#1,201 – How to Share Star Sized Column Sizes

You can use the SharedSizeGroup attribute to share column sizes across different grids. You can’t normally share sizes of star-sized columns across multiple grids, however, since star sizing works only in the context of the current grid.

Below is an example of how to get a star sized column to be the same size as a star sized column in a different grid. In the example, we have two grids. In the first, we have two auto-sized TextBlocks and then a star-sized TextBox that takes up the remaining space. In the second grid, we have just a TextBlock and a TextBox, but we want the TextBox to be the same size as the one in the first grid. Using SharedSizeGroup on the TextBox columns won’t work, since the columns would then get auto-sized.

The solution is to set up a SharedSizeGroup on every column except for the TextBox columns and to add a dummy third column in the second grid. The TextBox columns will then each independently use star sizing and end up the same size.

    <StackPanel Margin="15" Grid.IsSharedSizeScope="True">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" SharedSizeGroup="A"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto" SharedSizeGroup="B"/>
            </Grid.ColumnDefinitions>

            <TextBlock Grid.Column="0" Text="Col 1"/>
            <TextBox Grid.Column="1" />
            <TextBlock Grid.Column="2" Text="3rd column here"/>
        </Grid>

        <Separator Margin="0,20"/>

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" SharedSizeGroup="A"/>
                <ColumnDefinition />
                <ColumnDefinition SharedSizeGroup="B"/>
            </Grid.ColumnDefinitions>

            <TextBlock Grid.Column="0" Text="1"/>
            <TextBox Grid.Column="1"/>
        </Grid>
    </StackPanel>

1201

#1,200 – Overriding a Default Style

In WPF, you often set up default styles to set a series of properties on all instances of a certain type of element. Below, we set a default style that applies to all TextBlock elements, using the TargetType attribute. All properties in the style will be set for all instances of the TextBlock element.

<Window.Resources>
    <ResourceDictionary>
        <Style TargetType="TextBlock">
            <Setter Property="Foreground" Value="Purple"/>
            <Setter Property="FontStyle" Value="Italic"/>
        </Style>
    </ResourceDictionary>
</Window.Resources>

<StackPanel Margin="10">
    <TextBlock Text="Fafnir"/>
    <TextBlock Text="Siegfried"/>
    <TextBlock Text="Brynhildr"/>
</StackPanel>

1200_01

Sometimes you’ll be working in an environment where these default styles have been defined for you, but you want to override them.

The first way to override a default style is to define one of your own. Below, we define a named style and use it on the second TextBlock. (The style is added to the ResourceDictionary that we showed above).

<Style x:Key="BlueBig" TargetType="TextBlock">
   <Setter Property="Foreground" Value="Blue"/>
   <Setter Property="FontSize" Value="20"/>
</Style>
<TextBlock Text="Siegfried" Style="{StaticResource BlueBig}"/>

1200_02
The second way to override a default style is to revert the element to having no style at all using the x:Null markup extension. Below, the default style exists in our application but the first and third elements indicate that that they don’t want to use it. Notice that these TextBlocks appear normally.

<TextBlock Text="Fafnir" Style="{x:Null}"/>
<TextBlock Text="Siegfried" Style="{StaticResource BlueBig}"/>
<TextBlock Text="Brynhildr" Style="{x:Null}"/>

1200_03

#1,199 – Complete WPF Command Example

Below is a cheat sheet for creating a custom command in WPF.

Use a static property to expose a command object from the ViewModel or code-behind. RoutedUICommand allows for associating control text with the command itself.

private static RoutedUICommand _pressMeCommand = 
    new RoutedUICommand("Press Me", "PressMe", typeof(MainWindow));
public static RoutedUICommand PressMeCommand
{
    get { return _pressMeCommand; }
}

Add command handlers (in code-behind or ViewModel).

private void PressMe_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = CowboyCanTalk;
}
 
private void PressMe_Executed(object sender, ExecutedRoutedEventArgs e)
{
    MessageBox.Show("Howdy howdy I'm a cowboy");
}

Bind the command to its handlers, done here in XAML for a window.

<Window.CommandBindings>
    <CommandBinding Command="local:MainWindow.PressMeCommand" 
                    CanExecute="PressMe_CanExecute" 
                    Executed="PressMe_Executed"/>
</Window.CommandBindings>

Wire a button up to the command. Note use of command’s Text property for the button’s Content (text).

<Button Command="local:MainWindow.PressMeCommand" 
        Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}" />

We can also wire up the command to other GUI elements, e.g. a menu item in a context menu. The menu item’s text is set up automatically.

<Window.ContextMenu>
    <ContextMenu>
        <MenuItem Command="{x:Static local:MainWindow.PressMeCommand}" />
    </ContextMenu>
</Window.ContextMenu>