Пользовательский элемент управления WPF: свойство зависимости от типа коллекции

#c# #wpf #custom-controls #dependency-properties

#c# #wpf #пользовательские элементы управления #свойства зависимости

Вопрос:

У меня есть, CustomControl который содержит ListBox :

 <UserControl x:Class="WpfApplication1.CustomList"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <ListBox Name="listBox1" ItemsSource="{Binding ListSource}" />
    </Grid>
</UserControl>
  

Я связываю ItemsSource со свойством в коде, лежащем в основе:

 public partial class CustomList : UserControl, INotifyPropertyChanged
    {
        public CustomList( )
        {
            InitializeComponent( );
        }

        public ObservableCollection<object> ListSource
        {
            get
            {
                return (ObservableCollection<object>)GetValue( ListSourceProperty );
            }
            set
            {
                base.SetValue(CustomList.ListSourceProperty, value);
                NotifyPropertyChanged( "ListSource" );
            }
        }

        public static DependencyProperty ListSourceProperty = DependencyProperty.Register(
             "ListSource",
             typeof( ObservableCollection<object> ),
             typeof( CustomList ),
             new PropertyMetadata( OnValueChanged ) );

        private static void OnValueChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            ( (CustomList)d ).ListSource = (ObservableCollection<object>)e.NewValue;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged( string propertyName )
        {
            if(PropertyChanged != null)
            {
                PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
            }
        }
    }
  

Теперь в моем MainWindow я пытаюсь связать ObservableCollection «Статьи» с моим CustomControl и его свойством зависимости ListSource:

 <Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:local="clr-namespace:WpfApplication1"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <local:CustomList ListSource="{Binding Articles}"/>
    </Grid>
</Window>
  

И ошибка, которую я получаю:

 Error: 1 : Cannot create default converter to perform 'one-way' conversions between types 'System.Collections.ObjectModel.ObservableCollection`1[WpfApplication1.Article]' and 'System.Collections.ObjectModel.ObservableCollection`1[System.Object]'
  

Если в пользовательском элементе управления у меня есть ObservableCollection<Article> вместо ObservableCollection<object> , это работает.
Итак, есть ли способ, которым я могу связать свойство зависимости моего пользовательского элемента управления с ObservableCollection объектов без необходимости указывать тип объекта?

Комментарии:

1. Вам не нужно (фактически не должно) реализовывать INotifyPropertyChanged для DependencyProperties, также не размещайте какой-либо код в установщике параметра зависимости.

2. @H.B. Вы хотите сказать, что свойство dependency автоматически реализует надлежащие уведомления об изменениях? Или вы предполагаете, что есть лучшая альтернатива?

3. @UB3571: Да, они реализуют уведомления об изменениях, но они вводят привязку к потоку. Альтернативой, как я уже сказал, является INotifyPropertyChanged .

4. (Как ресурс для других) Относительно того, что входит в создание пользовательских зависимостей. реквизиты: я решил, прочитав эту ссылку , в которой полностью рассказывается о свойствах пользовательских зависимостей, и эту статью , в которой говорится о привязке к потоку, модели потоков и о том, как использовать диспетчер в своих интересах. ( @H.B. вы, кажется, немного противоречите всем комментариям INotifyPropertyChanged… Я все еще действительно понятия не имею, что вы пытаетесь этим предложить … извините.)

5. Проще было бы: нет необходимости в INotifyPropertyChanged для свойств зависимостей, поскольку они имеют встроенный SetValue метод, который уже выполняет свою работу здесь, устанавливая локальное значение, заданное идентификатором. Ничто другое не подписывается на событие PropertyChanged, так зачем вызывать событие, не зависящее от потока? Я ценю ваши комментарии, но вместо того, чтобы указывать людям, что делать, чтобы показать, что вы знаете об улучшении, пожалуйста, помогите нам улучшить самих себя, включив причинно-следственные рассуждения в ваши заявления 🙂 Если вы не возражаете. Все «довольно просто», как только вы это понимаете

Ответ №1:

Измените тип ListSource на IEnumerable, тогда вы сможете привязываться к любой коллекции.

Комментарии:

1. Спасибо за быстрый ответ, вы полностью спасли положение.

2. Согласно этому сообщению в блоге, вам следует использовать IList , чтобы вы также могли заполнять в thrown xaml . sshumakov.com/2012/11/13 /…