Welcome to the Xceed Community | Help
Community Search  
More Search Options

DON'T PANIC!

Life, the Universe, and Bindings

For most of the examples in the documentation, I chose to expose a static property in the application through which the data provided to the DataGridCollectionViewSource is retrieved. Now, this seems to have caused a lot of confusion; therefore, I will attempt to clarify the situation, but before I do I need to explain the difference between a Binding's Source, RelativeSource, and ElementName properties. The first major difference is that these properties are mutually exclusive, meaning that only one of them can be set on a Binding.

The Source property is used to specify an object reference on which the binding Path or XPath will be evaluated and is usually used when the object on which the Binding is set is known and differs from the DataContext.

<TextBox Text="{Binding Source={x:Static Application.Current}, Path=Information}"/>

In the example above, the Source is set to the Application.Current object and uses the x:Static markup extension to access a static object. Another example could be to use the Source property to access a resource defined in a resource dictionary:

<TextBox Text="{Binding Source={StaticResource myInformation}}"/>

The RelativeSource property is used to specify as a source an object that is positioned relatively to the current object. Once again, this property is used when there is a need to specify a source other than the DataContext of the object. There are three normal ways of using of the RelativeSource property.

The first usage is to access Self, which allows referencing itself as the source. This is particularly useful in styles or when we want to bind a property of an object on another property of the same object. 

<TextBlock Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}"/>

The second usage of RelativeSource is FindAncestor mode. FindAncestor mode allows the retrieval of an ancestor of the current object based on its type and/or an ancestor level. While the Type is mandatory, the level is not. If level is not specified or if the provided value does not have a match, then the first element with matching Type is used (i.e., if 1 is specified, the first occurrence of Type is used; if 3 is used, the third occurrence of Type will be used).

<StackPanel Background="Blue">
   <TextBlock Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}, AncestorLevel=1},Path=Background}" />
</StackPanel>

The third usage is TemplatedParent mode, which allows the retrieval of the object being templated (if within a template). If you are within a ControlTemplate, templating a Button, then the result of the TemplatedParent RelativeSource will be the Button object instance.

<Window>
   <Window.Resources>
      <ControlTemplate x:Key="myButtonTemplate" TargetType="{x:Type Button}">
         <StackPanel Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"/>
      </ControlTemplate>
   </Window.Resources>

   <Button Template="{StaticResource myButtonTemplate}" Background="Blue"/>
</Window>

The ElementName property is used to reference an object by the name of the object. This is particularly useful in XAML, where you can directly reference other elements defined in XAML.

<StackPanel Background="Blue">
   <Button x:Name="refButton" Background="Orange"/>
   <Button Background="{Binding ElementName=refButton, Path=Background}"/>
</StackPanel>

Any of these bindings could have been used to provide data to the DataGridCollectionViewSource; however, I decided to use a Source binding and reference the static property defined in the application (Appl.xaml.cs) using the x:Static markup extension, which evaluates the property before the remainder of the XAML is loaded, meaning that my data would be loaded before the grid is created. Unfortunately, this has caused many people to believe that the data can only be provided through a static property defined in the application, which is not the case. Now, using the Source property implies that the Path is not evaluated against the DataContext; however, even if I were to create a property and expose it through the Window that contains the datagrid, the binding would fail since the DataContext of the Window is not the Window itself. That said, I could use a RelativeSource/AncestorType binding to retrieve the Window and set the Path to the property:

<xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
                                   Source="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:Window1}}, Path=Orders}"/>

or I could set the Window's DataContext to itself and bind directly to the property:

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

<xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
                                   Source="{Binding Path=Orders}"/>

So remember: the location of the property is not important. Just choose the appropriate binding to access it and you will be good to go!

Published November 12, 2008 10:37 AM by Jenny [Xceed]
Filed under: ,

Comments

 

Jonathan said:

I spent the better part of a day trying to figure out why my code wasn't working, reading tons of documentation and blogs, and this was the one that finally solved the problem. Thank you, thank you, thank you!

June 20, 2009 12:36 AM
 

David said:

Thanks, good stuff, helpful

June 25, 2009 9:03 AM
Anonymous comments are disabled
Contact | Site Map | Reviews | Legal Terms of Use | Trademarks | Privacy Statement Copyright 2011 Xceed Software Inc.