Question

I'm trying to use WPF MultiBinding to target a custom property I defined on my UserControl. I'm not having any luck. All of the examples that I've seen target built-in .Net properties (Text, ItemSource, IsEnabled). I'm wondering if you can target a custom property. Please help.

///
public partial class ActivityStatusDisplay : UserControl
{


    public ActivityStatusDisplay()
    {
        InitializeComponent();
    }

    /// <summary>
    /// Gets or sets the value for the read/write property named 
    /// Status. 
    ///  
    /// </summary>
    public TaskStatuses Status
    {
        get
        {
            return (TaskStatuses)GetValue(StatusProperty);
        }
        set
        {
            SetValue(StatusProperty, value);

            UpdateForStatus(value);
        }
    }


    public static readonly DependencyProperty StatusProperty = DependencyProperty.
        Register("Status", typeof(TaskStatuses), typeof(ActivityStatusDisplay), null);

with the XAML for binding looking like one of these:

<my:DataGrid ItemsSource="{Binding PatientTaskCollection}">
                    <my:DataGrid.Columns>
                        <my:DataGridTemplateColumn Header="Status" Width="Auto">
                            <my:DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <my1:ActivityStatusDisplay Margin="3">
                                        <mb:BindingUtil.MultiBindings>
                                            <mb:MultiBindings>
                                                <mb:MultiBinding TargetProperty="Status" Converter="{StaticResource StatusConverter}">
                                                    <mb:MultiBinding.Bindings>
                                                        <mb:BindingCollection>
                                                            <Binding Path="RecoveryTaskStatusID"/>
                                                            <Binding Path="Due"/>
                                                        </mb:BindingCollection>
                                                    </mb:MultiBinding.Bindings>
                                                </mb:MultiBinding>
                                            </mb:MultiBindings>
                                        </mb:BindingUtil.MultiBindings>
                                    </my1:ActivityStatusDisplay>

or something like:

<my:DataGrid ItemsSource="{Binding PatientTaskCollection}">
                        <my:DataGrid.Columns>
                            <my:DataGridTemplateColumn Header="Status" Width="Auto">
                                <my:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <my1:ActivityStatusDisplay Margin="3">
                                            <my1:ActivityStatusDisplay.Status>
                                             <mb:MultiBinding Converter="{StaticResource StatusConverter}">
                                                                <Binding Path="RecoveryTaskStatusID"/>
                                                                <Binding Path="Due"/>

                                                    </mb:MultiBinding>
                                            </my1:ActivityStatusDisplay.Status>
Was it helpful?

Solution

You problem is that you are assuming the "setter" method for the Status property gets called when the binding changes its value. This is doesn't happen. Binding calls the SetValue method directly. Hence your call to UpdateForStatus doesn't occur when value is modified as a result of binding.

Here is how your dependency property should look, (I'll assume TaskStatuses is an enum type)

public TaskStatuses Status
{
    get { return (TaskStatuses)GetValue(StatusProperty); }
    set { SetValue(StatusProperty, value); }
}


public static readonly DependencyProperty StatusProperty =
  DependencyProperty.Register(
    "Status", 
    typeof(TaskStatuses), 
    typeof(ActivityStatusDisplay),
    new PropertyMetaData(TaskStatuses.Default, OnStatusPropertyChanged));

private static void OnStatusPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
   ActivityStatusDisplay source = (ActivityStatusDisplay)d;
   TaskStatuses value = (TaskStatuses)e.NewValue;
   source.UpdateForStatus(value);
}

Using the PropertyMetaData parameter of the Register method we can specify the default value this property should have and a static callback method to call whenever the value of the dependency property is changed. Its from this callback method that you would want to call your UpdateForStatus method.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top