.NET:事件难度大

时间:2010-11-14 17:25:09

标签: c# .net silverlight events

也许我完全不了解事件。

我正在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);

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

1 个答案:

答案 0 :(得分: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为空。您无法以这种方式连接事件。第二种方法是将事件连接起来的正确方法,上面的例子说明了你对此做了什么。