2010-11-14 59 views
2

也许我完全不理解事件。.NET:事件难点

我在Silverlight中构建了Windows Phone 7应用程序。

我有一个UserControl包装ListBox,称为EditableListBoxListBox有一个数据模板。列表框中的项目被包装在EditableListItem对象中。

数据模板如下:

<DataTemplate> 
    <Grid ManipulationCompleted="Grid_ManipulationCompleted"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="Auto"/> 
      <ColumnDefinition Width="*" /> 
     </Grid.ColumnDefinitions> 

     <Image Source="{Binding Path=IconSource}" 
       Grid.Column="0" 
       Width="96" 
       Height="96" 
       VerticalAlignment="Center" 
       Visibility="{Binding Path=Editing, Converter={StaticResource visibilityConverter}}" 
       /> 

     <TextBlock Text="{Binding Path=Name}" Grid.Column="1" /> 

    </Grid> 
</DataTemplate> 

我绑定Visibility每个EditableListItem的属性,所以我需要实现INotifyPropertyChanged所以更新为后盾的项目都反映在UI。 (?右或者是有一个更简单的方法来做到这一点?)

EditableListItem

public class EditableListItem : INotifyPropertyChanged 
{ 
    private EditableListBox _parentListBox; 

    public event PropertyChangedEventHandler PropertyChanged; 

    public bool Editing 
    { 
     get 
     { 
      return _parentListBox.Editing; 
     } 
    } 

    public EditableListItem(Section section, EditableListBox parentListBox) 
    { 
     _parentListBox = parentListBox; 

     // after this line, _parentListBox.PropertyChanged is still null. 
     // why is that? 
     _parentListBox.PropertyChanged += PropertyChanged; 

     _parentListBox.PropertyChanged += new PropertyChangedEventHandler(_parentListBox_PropertyChanged); 
    } 

EditableListBox

public partial class EditableListBox : UserControl, INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    // NotifyPropertyChanged will raise the PropertyChanged event, 
    // passing the source property that is being updated. 
    public void NotifyPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public void SetSectionsSource(ObservableCollection<Section> sectionsSource) 
    { 
     sectionsSource.CollectionChanged += new NotifyCollectionChangedEventHandler(sectionsSource_CollectionChanged); 
     ContentListBox.ItemsSource = sectionsSource.Select(section => new EditableListItem(section, this) { Enabled = true }); 
     //ContentListBox.ItemsSource.Add(new EditableListItem(new Section("Section", 3)) { Enabled = true }); 
    } 

    // ... 

    private bool _editing; 
    public bool Editing 
    { 
     get 
     { 
      return _editing; 
     } 
     set 
     { 
      _editing = value; 
      NotifyPropertyChanged("Editing"); 
     } 
    } 

} 

Editing属性存储在EditableListBox - EditableListItem只是将其转发。我想连接到EditableListItem.PropertyChanged直接EditableListBox.PropertyChanged,但下面不工作:

// after this line, _parentListBox.PropertyChanged is still null. 
    // why is that? 
    _parentListBox.PropertyChanged += PropertyChanged; 

下面做工作:

_parentListBox.PropertyChanged += new PropertyChangedEventHandler(_parentListBox_PropertyChanged); 

这是为什么?第一次尝试完全无效(如果是这样,为什么编译器允许它?)?

回答

2

首先,你不要连接PropertyChanged来实现它。这个想法是,WPF使用该事件并将其连接起来。您所做的唯一事情就是在适用时触发事件。

这就是问题的一部分。您有Editing属性,但它没有被解雇。我确实知道你已经连线父列表框的PropertyChanged以使事件触发,但这不起作用。

如果我明白了,想要完成的是当列表框的Editing属性发生变化时,您希望强制列表项的PropertyChanged

PropertyChanged的其中一件事是发件人已将设置为PropertyChanged所在的对象。这意味着你应该实现这样的:

public partial class EditableListBox : UserControl, INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    // You really should make this protected. You do not want the outside world 
    // to be able to fire PropertyChanged events for your class. 
    protected void NotifyPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    private bool _editing; 
    public bool Editing 
    { 
     get 
     { 
      return _editing; 
     } 
     set 
     { 
      _editing = value; 
      NotifyPropertyChanged("Editing"); 
     } 
    } 
} 

public class EditableListItem : INotifyPropertyChanged 
{ 
    private EditableListBox _parentListBox; 

    public EditableListItem(EditableListBox parentListBox) 
    { 
     _parentListBox = parentListBox; 

     _parentListBox.PropertyChanged += new PropertyChangedEventHandler(_parentListBox_PropertyChanged); 
    } 

    void _parentListBox_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     // Forward the event. 
     if (e.PropertyName == "Editing") 
      NotifyPropertyChanged("Editing"); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    // You really should make this protected. You do not want the outside world 
    // to be able to fire PropertyChanged events for your class. 
    protected void NotifyPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public bool Editing 
    { 
     get 
     { 
      return _parentListBox.Editing; 
     } 
    } 
} 

我不知道你是怎么得到的参考编辑列表框,但可以说你通过构造得到它。当您获得参考时,您将附加列表框的PropertyChanged事件处理程序。因为当该对象的Editing属性更改时,实际上,Editing属性也会发生更改。这是你如何模拟的。

最后一两件事:为什么PropertyChanged仍然null+= PropertyChanged是因为物体本身的PropertyChanged是空的原因。你不能以这种方式连接事件。第二种方式是接线事件的正确方式,上面的例子显示了你如何处理这些事件。

+0

感谢您的详细回复。那么,eventA + = eventB'实际上做了什么? – 2010-11-14 19:23:03

+0

我不太确定。从逻辑上讲,它会将附加到'eventB'的所有事件句柄复制到'eventA',但我怀疑这是因为它不应该从类外部访问事件的内容。我将不得不做一些测试。至少它注意到我以前曾经使用过。 – 2010-11-14 19:49:27