Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating one dependency property from another

I have a string dependency property (SearchText), when updated, needs to update a collection dependency property (Results).
My collection dp:

public IEnumerable<string> Results{
  get { return (IEnumerable<string>) GetValue(ResultsProperty); }
  set { SetValue(ResultsProperty, value); }
}
public static readonly DependencyProperty ResultsProperty= 
DependencyProperty.Register("Results", typeof(IEnumerable<string>), typeof(MainWindowVM), new UIPropertyMetadata(new List<string>()));

I tried this with no luck. i put a breakpoint at the Results = .... line and it never got hit.

public string SearchText{
  get { return (string) GetValue(SearchTextProperty); }
  set {
    Results =
          from T in Tree.GetPeople(value)
          select T.FullName;
    SetValue(SearchTextProperty, value);
  }
}
public static readonly DependencyProperty SearchTextProperty= 
DependencyProperty.Register("SearchText", typeof(string), typeof(MainWindowVM), new UIPropertyMetadata(""));

XAML:

<TextBox DockPanel.Dock="Top" Text="{Binding SearchValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

<ListBox DockPanel.Dock="Top" ItemsSource="{Binding NameResults}" SelectedItem="{Binding Search}" />

like image 379
Rob Avatar asked Aug 28 '09 13:08

Rob


2 Answers

When setting a dependency property in XAML or through a binding, the runtime will always bypass the instance property alias and directly call GetValue and SetValue. It is because of this that your instance setter isn't being invoked.

What you may wish to consider doing is registering a method with the dependency property which will be invoked when the property changes. This is most easily done when creating the PropertyMetadata for the dependency property.

I believe the following example does what you're looking to do. In the example, my class has two depencency properties aliased as First and Second. When I set the value for First, my change handler is invoked and I set the value of Second.

public class DependencyPropertyTest : DependencyObject
{
  public static readonly DependencyProperty FirstProperty;
  public static readonly DependencyProperty SecondProperty;

  static DependencyPropertyTest()
  {
    FirstProperty  = DependencyProperty.Register("FirstProperty", 
                                                  typeof(bool), 
                                                  typeof(DependencyPropertyTest), 
                                                  new PropertyMetadata(false, FirstPropertyChanged));

    SecondProperty = DependencyProperty.Register("SecondProperty", 
                                                 typeof(string), 
                                                 typeof(DependencyPropertyTest), 
                                                 new PropertyMetadata(null));
  } // End constructor

  private bool First
  {
    get { return (bool)this.GetValue(FirstProperty); }
    set { this.SetValue(FirstProperty, value);       }

  } // End property First

  private string Second
  {
    get { return (string)this.GetValue(SecondProperty); }
    set { this.SetValue(SecondProperty, value);         }

  } // End property Second

  private static void FirstPropertyChanged(DependencyObject dependencyObject, 
                                           DependencyPropertyChangedEventArgs ea)
  {
    DependencyPropertyTest instance = dependencyObject as DependencyPropertyTest;

    if (instance == null)
    {
      return;
    }

    instance.Second = String.Format("First is {0}.", ((bool)ea.NewValue).ToString());

  } // End method FirstPropertyChanged
} // End class DependencyPropertyTest

I hope that helps.

like image 97
Jesse Squire Avatar answered Nov 15 '22 07:11

Jesse Squire


As I commented, the currently accepted answer is correct in the principle, except that it MUST use the SetCurrentValue method instead of doing a simple assignment. See this answer for more explanation about it.

Here is the same code with this fix:

public class DependencyPropertyTest : DependencyObject
{
  public static readonly DependencyProperty FirstProperty;
  public static readonly DependencyProperty SecondProperty;

  static DependencyPropertyTest()
  {
    FirstProperty  = DependencyProperty.Register("FirstProperty", 
                                                  typeof(bool), 
                                                  typeof(DependencyPropertyTest), 
                                                  new PropertyMetadata(false, FirstPropertyChanged));

    SecondProperty = DependencyProperty.Register("SecondProperty", 
                                                 typeof(string), 
                                                 typeof(DependencyPropertyTest), 
                                                 new PropertyMetadata(null));
  } // End constructor

  private bool First
  {
    get { return (bool)this.GetValue(FirstProperty); }
    set { this.SetValue(FirstProperty, value);       }

  } // End property First

  private string Second
  {
    get { return (string)this.GetValue(SecondProperty); }
    set { this.SetValue(SecondProperty, value);         }

  } // End property Second

  private static void FirstPropertyChanged(DependencyObject dependencyObject, 
                                           DependencyPropertyChangedEventArgs ea)
  {
    DependencyPropertyTest instance = dependencyObject as DependencyPropertyTest;

    if (instance == null)
    {
      return;
    }

    // SetCurrentValue should be used here!
    instance.SetCurrentValue(SecondProperty,
      String.Format("First is {0}.", ((bool)ea.NewValue).ToString());

  } // End method FirstPropertyChanged
} // End class DependencyPropertyTest
like image 33
Benlitz Avatar answered Nov 15 '22 05:11

Benlitz