Можно ли связать свойство Canvas’s Children в XAML?

Я немного удивлен, что невозможно установить привязку для Canvas.Children через XAML. Мне приходилось прибегать к подходу с кодом, который выглядит примерно так:

private void UserControl_Loaded(object sender, RoutedEventArgs e) { DesignerViewModel dvm = this.DataContext as DesignerViewModel; dvm.Document.Items.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Items_CollectionChanged); foreach (UIElement element in dvm.Document.Items) designerCanvas.Children.Add(element); } private void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { ObservableCollection collection = sender as ObservableCollection; foreach (UIElement element in collection) if (!designerCanvas.Children.Contains(element)) designerCanvas.Children.Add(element); List removeList = new List(); foreach (UIElement element in designerCanvas.Children) if (!collection.Contains(element)) removeList.Add(element); foreach (UIElement element in removeList) designerCanvas.Children.Remove(element); } 

Я бы скорее просто установил привязку в XAML следующим образом:

   

Есть ли способ сделать это, не прибегая к подходу, основанному на коде? Я сделал некоторые поиски по этой теме, но не придумал много для этой конкретной проблемы.

Мне не нравится мой текущий подход, потому что он замалчивает мой красивый Model-View-ViewModel, заставляя View знать о его ViewModel.

Я не верю, что можно использовать привязку к свойству Children. Я на самом деле пытался это сделать сегодня, и это на меня напало, как и вы.

Холст – очень рудиментарный контейнер. Он действительно не предназначен для такого рода работ. Вы должны изучить один из многих элементов ItemsControls. Вы можете привязать ObservableCollection модели ViewModel к моделям ItemsSource и использовать DataTemplates для обработки того, как каждый элемент отображается в элементе управления.

Если вы не можете найти элемент ItemsControl, который отображает ваши элементы удовлетворительным образом, вам может потребоваться создать настраиваемый элемент управления, который сделает то, что вам нужно.

                

Другие дали экстенсивные ответы о том, как делать то, что вы на самом деле хотите сделать уже. Я просто объясню, почему вы не смогли напрямую привязать Children .

Проблема очень проста: цель привязки данных не может быть только для чтения, а Panel.Children только для чтения. Там нет специальной обработки для коллекций. Напротив, ItemsControl.ItemsSource является свойством чтения / записи, даже если он имеет тип коллекции – редкое явление для .NET-classа, но для поддержки сценария привязки.

ItemsControl предназначен для создания динамических коллекций элементов управления пользовательского интерфейса из других коллекций, даже для коллекций данных, отличных от UI.

Вы можете создать шаблон ItemsControl для рисования на Canvas . Идеальный способ – установить панель поддержки на Canvas а затем установить свойства Canvas.Left и Canvas.Top для непосредственных детей. Я не мог заставить это работать, потому что ItemsControl обертывает своих детей контейнерами, и трудно установить свойства Canvas в этих контейнерах.

Вместо этого я использую Grid как bin для всех предметов и рисую их каждый на своем Canvas . При таком подходе есть некоторые накладные расходы.

               

Вот код, который я использовал для создания исходной коллекции:

 List points = new List(); points.Add(new MyPoint(2, 100)); points.Add(new MyPoint(50, 20)); points.Add(new MyPoint(200, 200)); points.Add(new MyPoint(300, 370)); Collection.ItemsSource = points; 

MyPoint – это настраиваемый class, который ведет себя как версия System . Я создал его, чтобы продемонстрировать, что вы можете использовать свои собственные пользовательские classы.

Одна деталь: вы можете привязать свойство ItemsSource к любой коллекции, которую хотите. Например:

  

Для получения дополнительной информации о ItemsControl и о том, как это работает, ознакомьтесь с этими документами: Справочник по библиотеке MSDN ; Шаблоны данных ; Серия Dr WPP по ItemsControl .

 internal static class CanvasAssistant { #region Dependency Properties public static readonly DependencyProperty BoundChildrenProperty = DependencyProperty.RegisterAttached("BoundChildren", typeof (object), typeof (CanvasAssistant), new FrameworkPropertyMetadata(null, onBoundChildrenChanged)); #endregion public static void SetBoundChildren(DependencyObject dependencyObject, string value) { dependencyObject.SetValue(BoundChildrenProperty, value); } private static void onBoundChildrenChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { if (dependencyObject == null) { return; } var canvas = dependencyObject as Canvas; if (canvas == null) return; var objects = (ObservableCollection) e.NewValue; if (objects == null) { canvas.Children.Clear(); return; } //TODO: Create Method for that. objects.CollectionChanged += (sender, args) => { if (args.Action == NotifyCollectionChangedAction.Add) foreach (object item in args.NewItems) { canvas.Children.Add((UIElement) item); } if (args.Action == NotifyCollectionChangedAction.Remove) foreach (object item in args.OldItems) { canvas.Children.Remove((UIElement) item); } }; foreach (UIElement item in objects) { canvas.Children.Add(item); } } } 

И используя:

  
  • Похоже, что привязки данных не обновляются
  • Принуждение WPF TextBox больше не работает в .NET 4.0
  • Обнаружение ошибок проверки WPF
  • Связывание в WPF с элементом массива, заданным свойством
  • ItemsControl с несколькими DataTemplates для viewmodel
  • Связывающие свойства в коде
  • Общий class наблюдаемого словаря для DataBinding / WPF C #
  • Для чего нужен DataContext?
  • Когда следует использовать # и = в элементах управления ASP.NET?
  • Какие подходы доступны для фиктивных данных времени разработки в WPF?
  • Связывание WPF ComboBox с пользовательским списком
  • Interesting Posts
    Давайте будем гением компьютера.