.NET: трудности с событиями - PullRequest
2 голосов
/ 14 ноября 2010

Возможно, я не понимаю события полностью.

Я создаю приложение для Windows Phone 7 в Silverlight.

У меня есть UserControl, который окутывает ListBox, называемый EditableListBox. У ListBox есть шаблон данных. Элементы в окне списка обернуты 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, чтобы обновления элементов поддержки отражались в пользовательском интерфейсе. (Верно? Или есть более простой способ сделать это?)

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 Ответ

2 голосов
/ 14 ноября 2010

Для начала, вы не подключите 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 самого объекта равно нулю.Вы не можете связать события таким образом.Второй способ - это правильный способ связывания событий, и приведенный выше пример показывает, что вы делаете с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...