Home > Posts > HowTo: Bind to a DataContext property named Source in XAML

HowTo: Bind to a DataContext property named Source in XAML

While refactoring ClipFlair code to use MVVM (Model-View-ViewModel) pattern, I came across the XAML error “Object reference not set to an instance of an object.”, shown in Visual Studio when trying to bind to my ViewModel (accessed implicitly, being set as the DataContext of the XAML control) for a property named Source.

I have settled down to using the following MVVM-style pattern (of my own) at ClipFlair:

image

Update: Later on, at ClipFlair project, I renamed folder “Views” to “ViewModels” and folder “Components” to “Views” and moved “ViewModels” folder inside the “Views” one to keep view-related stuff in one place.

IImageViewer.cs:

image

ImageView.cs:

image

Update: Later on, I refactored this to initialize the fields directly instead of at the constructor:

//can set fields directly here or at the constructor     
private Uri source = IImageViewerDefaults.DefaultSource;

ImageViewerWindow.xaml.cs (the so-called codebehind for the XAML control):

image

Note above how we set the “DataContext” of the control to our ViewModel, so that we can bind to its properties implicitly (without referencing it) in the XAML.

Update: There’s something very important I had forgotten to do at the implementation of the “View” property in the code above, that is to listen for PropertyChangeEvents emitted by the ViewModel. In specific, we need to listen for changes of the ViewModel’s “Source” property to keep the View’s “SourceProperty” (a DependencyProperty that is also accessed via the View’s “Source” property) in sync with the ViewModel’s “Source” property. So the code shown in the above screenshot has to be fixed by changing the “View” property’s implementation like below:

image

For extra safety in case you want to allow setting a null ViewModel to the View property, you could check for (value != null) before trying to add PropertyChanged event handler to it:

if (value != null)

  value.PropertyChanged += new PropertyChangedEventHandler(View_PropertyChanged);

Obviously, if more DependencyProperties are added to the component (e.g. to be able to set them declaratively from XAML when instantiating the component) that have to be in sync to respective ones at the ViewModel (which is held by the View property), then the “View_PropertyChanged” method (event handler) implementation has to be extended with “else if” statements for each of those properties to set the respective dependency properties from the matching ViewModel properties.

BTW, if your ViewModel passes null to the changed property name to mark a single change event for multiple properties, then you have to also take that in mind (else you will get exception when you try to call “Equals” method on null string), by doing something like below:

if (e.PropertyName == null) {

Source = View.Source;

OtherProperty = View.OtherProperty;

//…sync all properties since we are not told which ones changed

return;

}

else if (e.PropertyName.Equals(“Source”) {

Source = View.Source;

}

else if (e.PropertyName.Equals(“OtherProperty”)

{

OtherProperty = View.OtherProperty;

}

//…

Note that instead of “.Equals” one could have also used “==” operator, since the C# compiler maps the string equality operator to string’s “.Equals” method.

Update: Another retouch I have since done to the code above is to avoid hardcoding property names and their default values and use nstead ithe proprerty name constants defined at the class IImageViewerProperties and the respective default values defined at IImageViewerDefaults. For example, I prefer to use (after adding a “using ClipFlair.Models.Views;” to the top):

public static readonly DependencyProperty SourceProperty =

DependencyProperty.Register(IImageViewerProperties.PropertySource, typeof(Uri), typeof(ImageWindow), new FrameworkPropertyMetadata(

(Uri)IImageViewerDefaults.DefaultSource,

new PropertyChangedCallback(OnSourceChanged)));

Update: I eventually opted for using a “switch” statement instead of nested if / else if statements, to keep things cleaner when more properties are added:

    protected void View_PropertyChanged(object sender, 
                                        PropertyChangedEventArgs e)
    {
       if (e.PropertyName == null)
       {
         Source = View.Source;
         //...
       }
       else switch (e.PropertyName)
           //string equality check in .NET uses ordinal (binary) comparison 
           //semantics by default
         {
           case IImageViewerProperties.PropertySource:
             Source = View.Source;
             break;
           //...
         }
     }

In an even newer iteration of that code, I removed the if/else and added the null check in the switch statement:

    protected void View_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
      switch (e.PropertyName) 
      {
        case null:
          Source = View.Source;
          //...
          break;
        case IImageViewerProperties.PropertySource:
          Source = View.Source;
          break;
        //...
       }
    }

ImageViewerWindow.xaml (the XAML control):

image

The issue at the last screenshot is that you can’t write Source=”{Binding Source}” as you’d write Source=”{Binding SomeDataContextProperty}”, but need to write Source=”{Binding Path=Source}” instead, since Source is a keyword at Binding expression syntax.

BTW, note that at the “edImageURL” TextBox I use Mode=TwoWay (two-way binding, the default is one way binding from source [the DataContext in our case] to target), whereas at the Image control I don’t. Both get an image URI from the ViewModel’s “Source” property, but we also want to be able to edit the URI at the textbox and update the view’s Source property (which will in turn update the Image control with the new image).

Also, note that apart from passing a URI to the Source property of an Image control there’s also a more verbose syntax one could use above, which can be handy to know of:

<Image>

<Image.Source>

<BitmapImage UriSource=”{Binding Path=Source}” />

</Image.Source>

</Image>

The <Image.Source> tag here is using the so-called property element syntax pattern. In the snippet above it sets a value to the Source property of the Image tag. XAML can use both XML attributes and child elements to set values to properties of controls, but whereas the attribute name would be “Source”, the child element tag has to be “Image.Source”, not just “Source”, since the XML schema needs to have unique definitions for the XML tags, whereas multiple objects could define different Source properties causing naming collisions.

According to http://10rem.net/blog/2012/03/27/tip-binding-an-image-elements-source-property-to-a-uri-in-winrt-xaml this more verbose syntax is needed at Windows 8 Metro-style apps (that is for the WinRT API) for binding an Image to a URI (but since that article is back from March 2012, probably this is not an issue any more).

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

%d bloggers like this: