Пользовательский холст INotifyPropertyChanged - PullRequest
0 голосов
/ 01 июля 2018

У меня есть следующий пользовательский холст, который срабатывает при добавлении или удалении дочерних элементов.

public class CustomCanvas : Canvas, INotifyPropertyChanged
{
    protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
    {        
        OnPropertyChanged(new PropertyChangedEventArgs(""));
    }
    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, e);
    }

    public event PropertyChangedEventHandler PropertyChanged;
}    

У меня также есть список, в котором я хочу отобразить имена детей на холсте.

public void Button_Click_1(object sender, RoutedEventArgs e)
{
    shapes= new ObservableCollection<string>();
    foreach (FrameworkElement drawing in customCanvas.Children)
    {
        shapes.Add(drawing.Name);
    }
    listBox.ItemsSource = shapes;
}

Проблема, с которой я столкнулся, заключается в том, что список не обновляется, когда я добавляю какой-либо элемент Framework в свой Custom Canvas. Это требует от меня нажатия кнопки_1. Я думал, что ObservableCollection и InotifyPropertyChanged автоматически обновят мой список. Пожалуйста, помогите.

1 Ответ

0 голосов
/ 01 июля 2018

Вы хотите привязать содержимое списка к именам дочерних элементов CustomCanvas. Для этого вам нужна коллекция, которая реализует INotifyCollectionChanged. ObservableCollection является набором по умолчанию. К сожалению, свойство Children в CustomCanvas не реализует INotifyCollectionChanged.

Рабочий обходной путь будет таким: вы можете сохранить отдельную коллекцию ObservableCollection и обновить ее в OnVisualChildrenChanged.

public class CustomCanvas : Canvas, INotifyPropertyChanged
{
    public ObservableCollection<string> Names { get; } = new ObservableCollection<string>();

    protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
    {
        Names.Clear();
        foreach(FrameworkElement child in Children)
        {
            Names.Add(child.Name);
        }

        //Note: this is not needed for Binding to Names to work
        OnPropertyChanged(new PropertyChangedEventArgs(""));
    }

    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, e);
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

В xaml вы получите:

    <local:CustomCanvas
        x:Name="customCanvas"
        Width="100"
        Height="100"
        Margin="327,101,0,0"
        HorizontalAlignment="Left"
        VerticalAlignment="Top" />
    <ListBox
        Width="100"
        Height="100"
        Margin="638,201,0,0"
        HorizontalAlignment="Left"
        VerticalAlignment="Top"
        ItemsSource="{Binding Names, ElementName=customCanvas}">
    </ListBox>

Для информации: INotifyPropertyChanged не работает в вашем примере, так как сама коллекция Children является тем же объектом, и привязки не будут обновлены. Вот почему вам нужен реализующий коллекцию INotifyCollectionChanged (ObservableCollection).

Я также рекомендую вам использовать шаблон MVVM, если вы собираетесь использовать WPF с привязками данных. Это делает его более обтекаемым.

...