2013-12-07 6 views
1

Мне не повезло, чтобы связать коллекцию данных с моим пользовательским элементом управления своим свойством. Я уже реализовал механизм для свойства string этого элемента управления (с небольшой помощью отсюда) и ожидал, что тип коллекции будет таким же простым. Однако я не могу заставить его работать снова.Связывание коллекции с настраиваемым свойством управления

Вот мой пользовательский вид управления

<UserControl x:Class="BadaniaOperacyjne.Controls.Matrix" 
      mc:Ignorable="d" Name="CustomMatrix" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <!-- ... --> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <!-- ... --> 
     </Grid.ColumnDefinitions> 
     <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding ElementName=CustomMatrix, Path=Title}"/> 
     <Grid Grid.Row="2" Grid.Column="1" Name="contentGrid"> 
      <ListBox ItemsSource="{Binding ElementName=CustomMatrix, Path=ItemsList}"> 
       <ListBox.ItemTemplate> 
        <DataTemplate> 
         <TextBlock Text="{Binding}"/> 
        </DataTemplate> 
       </ListBox.ItemTemplate> 
      </ListBox> 
     </Grid> 
    </Grid> 
</UserControl> 

и его код-за

#region ItemsList Property 
public static readonly DependencyProperty ItemsListProperty = 
    DependencyProperty.Register("ItemsList", typeof(ObservableCollection<object>), typeof(Matrix), new PropertyMetadata(new ObservableCollection<object>(), new PropertyChangedCallback(ItemsListChanged))); 
public ObservableCollection<object> ItemsList 
{ 
    get { return GetValue(ItemsListProperty) as ObservableCollection<object>; } 
    set { SetValue(ItemsListProperty, value); } 
} 
private void ItemsListChanged(object value) 
{ 
    System.Diagnostics.Debug.WriteLine("matrix: items list changed " + value); 
    if (ItemsList != null) 
    { 
     ItemsList.CollectionChanged += ItemsList_CollectionChanged; 
     System.Diagnostics.Debug.WriteLine("got " + string.Join(",", ItemsList.ToList())); 
    } 
    else 
    { 
     System.Diagnostics.Debug.WriteLine("got null"); 
    } 
} 

void ItemsList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
{ 
    System.Diagnostics.Debug.WriteLine("matrix: current items list collection changed"); 
} 
private static void ItemsListChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    // a breakpoint 
    ((Matrix)d).ItemsListChanged(e.NewValue); 
} 
#endregion 

// showing the Title property implementation just to state that 
// it is done the same way as for ItemsList 
#region Title Property 
public static readonly DependencyProperty TitleProperty = 
    DependencyProperty.Register("Title", typeof(string), typeof(Matrix), new PropertyMetadata("", new PropertyChangedCallback(TitleChanged))); 
public string Title 
{ 
    get { return (string)GetValue(TitleProperty); } 
    set { SetValue(TitleProperty, value); } 
} 
private void TitleChanged(string title) 
{ 
    System.Diagnostics.Debug.WriteLine("matrix: title changed to: " + title); 
} 
private static void TitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    ((Matrix)d).TitleChanged((string)e.NewValue); 
} 
#endregion 

А вот как я пытаюсь связать с этим элементом управления

<custom:Matrix x:Name="customMatrix" DockPanel.Dock="Top" Title="{Binding Title}" ItemsList="{Binding Items}"/> 

и код -behind для главной страницы

//internal ObservableCollection<List<int>> ItemsList { get; set; } 
public class ViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public ViewModel() 
    { 
     Items = new ObservableCollection<int> { 1, 2, 3, 4, 5, 6}; 
    } 

    void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     System.Diagnostics.Debug.WriteLine("problem manager: items list changed " + e.NewItems.Count); 
    } 

    public ObservableCollection<int> Items { get; set; } 

    protected string title; 
    public string Title 
    { 
     get { return title; } 
     set 
     { 
      if (title != value) 
      { 
       title = value; 
       NotifyPropertyChanged("Title"); 
      } 
     } 
    } 

    protected void NotifyPropertyChanged(string name) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 
} 

public ViewModel VM { get; private set; } 

// this is the window constructor 
private ProblemManager() 
{ 
    VM = new ViewModel(); 

    DataContext = VM; 
    InitializeComponent(); 

    VM.Title = "title"; 
} 

private int i = 0; 
private void btnAddRow_Click(object sender, RoutedEventArgs e) 
{ 
    // when doing either of these two lines below, 
    // the control breakpoint is never hit 
    VM.Items.Add(++i); 
    VM.Items = new ObservableCollection<int> { 2, 3 }; 

    // however, when directly assigning to the control's property, 
    // the event is raised and the breakpoint is hit and the UI is updated 
    customMatrix.ItemsList = new ObservableCollection<object> { 1, 2, 3 }; 
    customMatrix.ItemsList.Add(66); 
    // and this of course makes the control's title update 
    VM.Title = (++i).ToString(); 
} 

Оба DependencyProperty s для управления Title и ItemsList, я считаю, созданы таким же образом. Тем не менее, привязка, вероятно, не работает, поскольку событие ItemsListChanged не связано с этим связыванием. Итак, проблема в том, что я не могу связать коллекцию моего окна ViewModel.Items через XAML с коллекцией управления ItemsList. Является ли создание DependencyProperty для коллекции в рамках элемента управления, отличного от DependencyProperty, для простого свойства string?

+0

Привязка к 'Title' работает или что тоже не работает? –

+0

Да, это не только изменяет значение свойства, но и обновляет пользовательский интерфейс. Единственное, что не работает на данный момент - это привязка «ItemsList» :( – patryk

+0

проверить разницу имен на одном месте его столицу c и другую ее маленькую c в CustomMatrix – ethicallogics

ответ

2

Проблема в вашей регистрации DependencyProperty. Co-variance is not applicable for generic lists т.е. вы не можете сделать это -

ObservableCollection<object> objects = new ObservableCollection<int>(); 

Вы объявили тип DP, как ObservableCollection<object> но связывая его со списком типа ObservableCollection<int>.

Вы должны change either type of DP to ObservableCollection<int> ИЛИ change binding collection type to ObservableCollection<object>.

public ViewModel() 
{ 
    Items = new ObservableCollection<object> { 1, 2, 3, 4, 5, 6}; 
} 

public ObservableCollection<object> Items { get; set; } 
+0

Это решило мою проблему, но если я получу это право, невозможно связать с любым типом типа я имею в виду, что я не могу подключить к нему набор строк или целых чисел. Или это возможно? – patryk

+0

Нет 'ObservableCollection ' не может быть привязан к 'ObservableCollection '. Вместо этого вы можете сделать тип возвращаемого значения 'IEnumerable', который может быть привязан к любой коллекции. –

+0

Даже свойство 'ItemsSource'' ItemsControl' имеет тип 'IEnumerable'. –

Смежные вопросы