Caller info attributes and WPF

In .Net 4.5 Framework besides the major change (support for asynchronous programming) guys from Microsoft have introduced a tiny feature which is useful for logging and debugging purposes: caller info attributes

  • CallerFilePathAttribute
  • CallerLineNumberAttribute
  • CallerMemberNameAttribute

For those who have used C++, the caller info attributes can be seen as equivalent of:

  • __FILE__
  • __LINE__
  • __FUNCTION__

Caller info attributes can applied optional method parameters. Once applying those attributes the compiler generates on method call site the corresponding information each attribute:

  • Full path of the source file that contains the caller (in case of CallerFilePathAttribute)
  • Line number in the source file at which the method is called (in case of CallerLineNumberAttribute)
  • Method or property name of the caller to the method (in case of CallerMemberNameAttribute)

Below you can see an example built with Visual Studio 2012 and .Net 4.5 Framework:

class Program
{
    static void Main(string[] args)
    {
        Trace();
    }

    static void Trace(
        [CallerMemberName] string memberName = "",
        [CallerFilePath] string sourceFilePath = "",
        [CallerLineNumber] int sourceLineNumber = 0)
    {
        Console.WriteLine("Member: {0}", memberName);
        Console.WriteLine("File: {0}", sourceFilePath);
        Console.WriteLine("Line: {0}", sourceLineNumber);
    }
}

After compiling and running the resulting output is:

Member: Main
File: c:\Users\marius\Documents\Visual Studio 2012\Projects\ConsoleApplication\ConsoleApplication\Program.cs
Line: 14

CallerMemberNameAttribute and WPF

For those who are building WPF application using the MVVM architectural pattern, the caller info attributes turn out to be useful.

Usually, in MVVM we have one ViewModel per View, the ViewModel implements INotifyPropertyChanged interface and contains several properties that the View binds to.

As an example I will create a small WPF application that contains only a Title and a TextBox,. Once the user writes something in the TextBox, the change will reflected in the Title.

We will start by defining the MainWindow.xaml:

<Window x:Class="WpfApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="{Binding Path=Title}">

    <Grid>

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <StackPanel Orientation="Horizontal" Margin="10">
        <Label Content="Add Title : "/>
        <TextBox Text="{Binding Path=Title, UpdateSourceTrigger=PropertyChanged}" MinWidth="150" />
    </StackPanel>

    </Grid>

</Window>

In the code behind we simply bind to a ViewModel:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        DataContext = new MainWindowViewModel();
    }
}

The next step will be to define the ViewModel. There are two options:

1. Previous to caller info attribute the MainWindowViewModel.cs looked like this:

internal class MainWindowViewModel : INotifyPropertyChanged
{
    private string _title;

    public string Title
    {
        get
        {
            return _title;
        }
        set
        {
            _title = value;
            RaisePropertyChanged("Title");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handlers = PropertyChanged;

        if (handlers != null)
        {
            handlers(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

2. With caller info attributes, MainWindowViewModel.cs can look like this:

internal class MainWindowViewModel : INotifyPropertyChanged
{
    private string _title;

    public string Title
    {
        get
        {
            return _title;
        }
        set
        {
            _title = value;
            RaisePropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(
        [CallerMemberName] string propertyName = "")
    {
        PropertyChangedEventHandler handlers = PropertyChanged;

        if (handlers != null)
        {
            handlers(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s