开发者

.NET: Difficulty with Events

Perhaps I don't understand events fully.

I'm building a Windows Phone 7 app in Silverlight.

I have a UserControl that wraps a ListBox, called EditableListBox. The ListBox has a data template. The items in the list box are wrapped by EditableListItem objects.

The data template is as follows:

<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>

I'm binding the Visibility to a property of each EditableListItem, so I need to implement INotifyPropertyChanged so updates to the backing items are reflected in the UI. (Right? Or is there a simpler way to do it?)

EditableListItem:

public class EditableListItem : INotifyPropertyChanged
{
    private EditableListBox _parentListBox;

    public event PropertyChangedEventHandler PropertyChanged;

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

    public EditableListItem(Section section, EditableLis开发者_Python百科tBox 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");
        }
    }

}

The Editing property is stored in EditableListBox - EditableListItem just forwards it. I wanted to attached EditableListItem.PropertyChanged to EditableListBox.PropertyChanged directly, but the following didn't work:

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

The following did work:

_parentListBox.PropertyChanged += new PropertyChangedEventHandler(_parentListBox_PropertyChanged);

Why is this? Is the first attempt totally invalid (if so, why does the compiler allow it?)?


To begin with, you don't wire up the PropertyChanged to implement it. The idea is that WPF uses that event and it wires it up. The only thing you do is trigger the event when applicable.

And that's a part of the issue here. You have the Editing property, but it is not being fired. I do understand that you have wired the PropertyChanged of the parent listbox to get the event to fire, but that is not going to work.

If I get the idea right, what you want to accomplish is when the Editing property of the listbox gets changed, you want the PropertyChanged of the list item to be forced.

One of the things of PropertyChanged is that the sender has to be the object where the PropertyChanged is located. This means that you should implement it like this:

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;
        }
    }
}

I don't know how you get the reference to the editable listbox, but lets say you get it via the constructor. When you get the reference, you attach the the PropertyChanged event handler of the listbox. Because, when the Editing property of that object changes, actually, your Editing property changes too. This is how you simulate that.

One last thing: the reason why the PropertyChanged is still null after the += PropertyChanged is because the PropertyChanged of the object itself is null. You cannot wire the events in this way. The second way is the correct way of wiring up the events, and the above example shows what you do with this.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜