7

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}" />

Rob
  • 2,080
  • 4
  • 28
  • 48

3 Answers3

15

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.

Jesse Squire
  • 6,107
  • 1
  • 27
  • 30
  • -1, This will break binding on the `Second` property because SetValue will be used instead of SetCurrentValue (see http://stackoverflow.com/questions/4230698/whats-the-difference-between-dependency-property-setvalue-setcurrentvalue). – Benlitz May 12 '14 at 09:42
  • 3
    True today, I'll grant you. However, at the time this answer was written, the .NET Framework 3.5 was the most current version which did not have a SetCurrentValue member. (ref: https://msdn.microsoft.com/en-us/library/system.windows.dependencyobject_members(v=vs.90).aspx) Well worth a comment or additional answer to modernize, but IMHO it doesn't warrant a down vote. – Jesse Squire Feb 14 '15 at 21:18
10

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
Community
  • 1
  • 1
Benlitz
  • 1,952
  • 1
  • 17
  • 30
0

The Order that you put on it your dependency property is very important the fist one put in the class file, will be executed fist then the one down to it

class A {
dependecy 1
dependecy 2 
dependecy 3
}

it will be called in the order set on the class, so just order your dependency on the order you want if 1 depend on 2 -> put 2 first, then 1 like this

class A {
dependecy 2 
dependecy 1
dependecy 3
}
Bilal
  • 1,254
  • 13
  • 14