WPFwiki, wpf, wiki, .net 3.0, windows presentation foundation, FAQ, free resources, solution, development, microsoft Home of the world's largest WPF FAQ
Edit

Category

Data Binding

Edit

Question

How can I declare a binding on a class method in XAML?

Edit

Answer

It is possible to perform a binding between a dependency property (as a target) and a class method (as a source). You have to use the ObjectDataProvider class to do this. There are two things to consider in this case.

First, Binding to an ObjectDataProvider is a special case of binding. It is handled differently by the binding engine. Instead of applying the binding on the ObjectDataProvider, the engine will apply it on the underlying object (the wrapped object). This is what we want when binding on a property wrapped by the ObjectDataProvider. However, this is not usually what we want when binding to a method. We typically want to bind a dependency property to the MethodParameters property of ObjectDataProvider. To tell the binding engine that we want to bind directly to the ObjectDataProvider (the call to the method) instead of the underlying object, we have to set the BindsDirectlyToSource property on the Binding object.

Second, because we bind on a MethodParameters (IList) instead of a strongly-typed property, we probably have to specify a ValueConverter to convert the value from the binding source to the binding target and vice versa. Naturally, this is unnecessary if the source and the target are of the same type.

In the following sample, we declare an ObjectDataProvider pointing on the static FromArgb method of the good old System.Drawing.Color class. Then, we declare three other ObjectDataProviders for each of the following member methods of the same class: GetBrightness, GetHue and GetSaturation. Each of these latter ObjectDataProviders uses the Color instance declared above.

Next, we look at the UI composition. The first notable content are three TextBoxes having their Text property bound to the first ObjectDataProvider ("call to FromArgb"). These constitute one example of method binding. Modifying the value of one of these TextBoxes will trigger the call to the "FromArg" resulting in a new color instance.

There is another method binding declaration, which is simpler because the methods bound to do not accept parameters. We only have to reference to the ObjectDataProvider by its resource key.

<Window x:Class="WindowsApplication4.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:system="clr-namespace:System" 
        xmlns:drawing="clr-namespace:System.Drawing;assembly=System.Drawing"
        xmlns:local="clr-namespace:WindowsApplication4"
        Title="CLR Property As Binding Target Sample"
        Height="300"
        Width="300">
   <Window.Resources>
      
      <ObjectDataProvider ObjectType="{x:Type drawing:Color}"
                          MethodName="FromArgb" 
                          x:Key="WorkingColor">
         <ObjectDataProvider.MethodParameters>
            <system:Int32>255</system:Int32>
            <system:Int32>255</system:Int32>
            <system:Int32>255</system:Int32>
            <system:Int32>255</system:Int32>
         </ObjectDataProvider.MethodParameters>
      </ObjectDataProvider>
      
      <ObjectDataProvider ObjectInstance="{StaticResource WorkingColor}"
                          MethodName="GetBrightness" 
                          x:Key="ColorBrightness">
      </ObjectDataProvider>
      <ObjectDataProvider ObjectInstance="{StaticResource WorkingColor}"
                          MethodName="GetHue" 
                          x:Key="ColorHue">
      </ObjectDataProvider>
      <ObjectDataProvider ObjectInstance="{StaticResource WorkingColor}"
                          MethodName="GetSaturation" 
                          x:Key="ColorSaturation">
      </ObjectDataProvider>
      <Style x:Key="LabelStyle"
             TargetType="{x:Type TextBlock}">
         <Setter Property="Margin"
                 Value="5,3,0,0"/>
      </Style>
      <local:IntToString x:Key="IntToString" />
   </Window.Resources>
   <StackPanel>
      <StackPanel Orientation="Horizontal">
         
         <TextBlock Text="R: "
                    Style="{StaticResource LabelStyle}"/>
         <TextBox Width="50"
                  Name="RPart" 
                  Text="{Binding Source={StaticResource WorkingColor}, Path=MethodParameters1, BindsDirectlyToSource=True, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IntToString}}"/>
         <TextBlock Text="G: "
                    Style="{StaticResource LabelStyle}"/>
         <TextBox Width="50"
                  Text="{Binding Source={StaticResource WorkingColor}, Path=MethodParameters2, BindsDirectlyToSource=True, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IntToString}}"/>
         <TextBlock Text="B: "
                    Style="{StaticResource LabelStyle}"/>
         <TextBox Width="50"
                  Text="{Binding Source={StaticResource WorkingColor}, Path=MethodParameters3, BindsDirectlyToSource=True, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IntToString}}"/>
      </StackPanel>
         
      <StackPanel Orientation="Horizontal">
         <TextBlock Text="Brightness: "/>
         <TextBlock Text="{Binding Source={StaticResource ColorBrightness}}"/>
      </StackPanel>
      <StackPanel Orientation="Horizontal">
         <TextBlock Text="Hue: "/>
         <TextBlock Text="{Binding Source={StaticResource ColorHue}}"/>
      </StackPanel>
      <StackPanel Orientation="Horizontal">
         <TextBlock Text="Saturation: "/>
         <TextBlock Text="{Binding Source={StaticResource ColorSaturation}}"/>
      </StackPanel>
   </StackPanel>
</Window>


As a bonus, here is the code for the IntToString ValueConverter:

public class IntToString : IValueConverter
{
  public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
  {
    if( value != null )
    {
      return value.ToString();
    }
    return null;
  }
  public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
  {
    string strValue = value as string;
    if( strValue != null )
    {
      int result;
      bool converted = int.TryParse( strValue, out result );
      if( converted )
      {
        return result;
      }
    }
    return null;
  }
}


Edit

Related Links


Using non dependency property as binding High School Assistance

All content is Copyright ©2007 Xceed Software Inc. unless otherwise indicated. See the Terms of Service. Contributors must read and agree to the Contribution Policy. WPFwiki is brought to you by Xceed, makers of the powerful yet free Xceed DataGrid for WPF.