2010-11-14 58 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