Silverlight监听属性变化
现有两个DataGrid:A、B,A是母表,B是子表。即B是A集合的一部分,当点击A的不同行时,B发生变化,列出选中行的详细。
简单来说,B的ItemsSource是不断变化的。那怎么监听B的ItemsSource呢,当ItemsSource变化时,有通知事件?首先想到的是依赖属性,但依赖属性只会跑一次,实现不了监听的功能。在谷歌上,找到一篇博客,实现我的功能。
http://blog.thekieners.com/2010/08/27/listening-to-dependencyproperty-changes-in-silverlight/
首先,要定义两个类。
DependencyPropertyChangedListener

1 using System; 2 using System.Windows; 3 using System.Windows.Data; 4 5 namespace Controls.Query.Helpers 6 { 7 /// <summary> 8 /// This class implements a listener to receive notifications for dependency property changes. 9 /// </summary> 10 public class DependencyPropertyChangedListener 11 { 12 #region Inner types 13 14 // Helper element to make it possible to use the binding engine to get notified when the source element property changes. 15 private sealed class RelayObject : DependencyObject 16 { 17 private DependencyPropertyChangedListener _listener; 18 19 internal RelayObject(DependencyPropertyChangedListener listener) 20 { 21 _listener = listener; 22 } 23 24 #region Value (DependencyProperty) 25 26 public object Value 27 { 28 get { return (object)GetValue(ValueProperty); } 29 set { SetValue(ValueProperty, value); } 30 } 31 public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(RelayObject), new PropertyMetadata(default(object), new PropertyChangedCallback(OnValueChanged))); 32 33 private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 34 { 35 object oldValue = (object)e.OldValue; 36 object newValue = (object)e.NewValue; 37 RelayObject source = (RelayObject)d; 38 source.OnValueChanged(oldValue, newValue); 39 } 40 41 private void OnValueChanged(object oldValue, object newValue) 42 { 43 _listener.OnValueChanged(oldValue, newValue); 44 } 45 46 #endregion 47 } 48 49 #endregion 50 51 #region Events 52 53 /// <summary> 54 /// Raises when the dependency property changes. 55 /// </summary> 56 public event EventHandler<DependencyPropertyValueChangedEventArgs> ValueChanged; 57 58 #endregion 59 60 #region Ctor 61 62 private DependencyPropertyChangedListener() 63 { 64 // just to make it private 65 } 66 67 #endregion 68 69 // holds a reference to the relay object in order that the GC does not collect it 70 private RelayObject RelayInstance { get; set; } 71 72 public static DependencyPropertyChangedListener Create(DependencyObject sourceElement, string propertyPath) 73 //public static DependencyPropertyChangedListener Create(DependencyObject sourceElement, DependencyProperty property) 74 { 75 // check input 76 if (sourceElement == null) 77 throw new ArgumentNullException("sourceElement"); 78 if (string.IsNullOrWhiteSpace(propertyPath)) 79 throw new ArgumentException("propertyPath is empty"); 80 81 // create listener 82 DependencyPropertyChangedListener listener = new DependencyPropertyChangedListener(); 83 84 // setup binding 85 Binding binding = new Binding(); 86 binding.Source = sourceElement; 87 binding.Mode = BindingMode.OneWay; 88 //binding.Path = new PropertyPath(property); // throws exception 89 binding.Path = new PropertyPath(propertyPath); 90 91 // create relay object 92 RelayObject relay = new RelayObject(listener); 93 // ...the listener holds a reference to the relay object in order that the GC does not collect it 94 listener.RelayInstance = relay; 95 96 // set binding 97 BindingOperations.SetBinding(relay, RelayObject.ValueProperty, binding); 98 99 return listener; 100 } 101 102 public void Detach() 103 { 104 if (this.RelayInstance != null) 105 { 106 // first: reset member to prevent further eventing of ValueChanged event. 107 RelayObject temp = this.RelayInstance; 108 this.RelayInstance = null; 109 110 // second: clear the binding -> raises property changed event... 111 temp.ClearValue(RelayObject.ValueProperty); 112 } 113 } 114 115 private void OnValueChanged(object oldValue, object newValue) 116 { 117 // raise event, but only if the listener is not detached. 118 if (ValueChanged != null && this.RelayInstance != null) 119 ValueChanged(this, new DependencyPropertyValueChangedEventArgs(oldValue, newValue)); 120 } 121 } 122 }
DependencyPropertyValueChangedEventArgs,继承EventArgs

1 using System; 2 3 namespace Controls.Query.Helpers 4 { 5 /// <summary> 6 /// Provides data for a DependencyPropertyChangedListener ValueChanged implementation. 7 /// </summary> 8 public class DependencyPropertyValueChangedEventArgs : EventArgs 9 { 10 internal DependencyPropertyValueChangedEventArgs(object oldValue, object newValue) 11 { 12 OldValue = oldValue; 13 NewValue = newValue; 14 } 15 16 /// <summary> 17 /// Gets the value of the property before the change. 18 /// </summary> 19 public object OldValue { get; private set; } 20 21 /// <summary> 22 /// Gets the value of the property after the change. 23 /// </summary> 24 public object NewValue { get; private set; } 25 } 26 }
在引用的地方这样写
1 private DependencyPropertyChangedListener listener; 2 3 public MainPage() 4 { 5 InitializeComponent(); 6 7 listener = DependencyPropertyChangedListener.Create(this, "BindingGrid.ItemsSource"); 8 listener.ValueChanged += ListenerValueChanged; 9 } 10 11 void ListenerValueChanged(object sender, DependencyPropertyValueChangedEventArgs e) 12 { 13 var itemsSource = BindingGrid.ItemsSource; 14 if (itemsSource != null) 15 { 16 //SourceInitialized(itemsSource); 17 } 18 } 19 20 public DataGrid BindingGrid 21 { 22 get { return (DataGrid)GetValue(BindingGridProperty); } 23 set { SetValue(BindingGridProperty, value); } 24 } 25 26 public static readonly DependencyProperty BindingGridProperty = 27 DependencyProperty.Register("BindingGrid", typeof(DataGrid), typeof(ConfigurableQueryer), 28 new PropertyMetadata(null, OnBindingGridChange)); 29 30 //只跑一次 31 private static void OnBindingGridChange(DependencyObject sender, DependencyPropertyChangedEventArgs e) 32 { 33 var configurableQueryer = sender as ConfigurableQueryer; 34 var dg = e.NewValue as DataGrid; 35 }
作者:Ivan