簡體   English   中英

如何在UserControl中綁定集合依賴項屬性

[英]How to bind collection dependency property in UserControl

這不是重復的! 當我失敗時,我嘗試尋找類似的帖子,但沒有成功。 我不明白為什么未調用OnUCItemsSourceChanged 我很確定我錯過了一些簡單的事情,但是找不到。

我有一個包含UserControl1 Window ,該Window具有附加的集合屬性,該屬性綁定到WindowWindowCollection集合。 我希望在向WindowCollection添加項目時調用UserControl1.OnUCItemsSourceChanged 但這不會發生。

我想念什么?

Window1.xaml.cs

public partial class Window1 : Window
{
    public ObservableCollection<long> WindowCollection { get; set; }
    public Window1()
    {
        InitializeComponent();

        DataContext = this;

        WindowCollection = new ObservableCollection<long>();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        WindowCollection.Add(1);
        WindowCollection.Add(2);
    }
}

Window1.xaml

<StackPanel>
    <uc:UserControl1 UCItemsSource="{Binding Path=WindowCollection}" />
    <Button Content="Refresh" Click="Button_Click" />
</StackPanel>

UserControl1.xaml.cs

public static readonly DependencyProperty UCItemsSourceProperty = DependencyProperty.Register("UCItemsSource", typeof(IEnumerable), typeof(UserControl1), new PropertyMetadata(null, new PropertyChangedCallback(OnUCItemsSourceChanged)));

public IEnumerable UCItemsSource
{
    get { return (IEnumerable)GetValue(UCItemsSourceProperty ); }
    set { SetValue(UCItemsSourceProperty , value); }
}

public ObservableCollection<MyItem> UCItems { get; set; }

private static void OnUCItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var control = d as UserControl1;
    var items = e.NewValue as ObservableCollection<long>;

    foreach (var item in items)
   {
         control.UCItems.Add(new MyItem(item));
   }
}

UserControl1.xaml

<ItemsControl ItemsSource="{Binding UCItems}" ... />

更新這是我的測試項目的鏈接

在這一行:

<ItemsControl ItemsSource="{Binding UCItems}" ... />

必須是帶有FindAncestor的RelativeSource ,因為UCItems位於UserControl中:

UserControl

<ItemsControl ItemsSource="{Binding Path=UCItems,
                                    RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" />

I cannot understand why OnUCItemsSourceChanged is not called?

如果添加RelativeSource構造,則OnUCItemsSourceChanged至少OnUCItemsSourceChanged引起一次,因為PropertyChangedCallback每次都會觸發,因此您需要為依賴項屬性設置新值:

表示當依賴項屬性的有效屬性值更改時調用的回調。

由於您曾經在此處設置依賴項屬性的值:

<uc:UserControl1 UCItemsSource="{Binding Path=WindowCollection}" />

I expect UserControl1.OnUCItemsSourceChanged to be called when I add items to WindowCollection.

為此,存在一個ObservableCollection<T>.CollectionChanged事件,其中包含對集合執行的動作的枚舉:

在添加,刪除,更改,移動項目或刷新整個列表時發生。

對於您的情況將是這樣的:

Version with CollectionChanged

MainWindow

public partial class MainWindow : Window
{
    public ObservableCollection<long> WindowCollection { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;

        WindowCollection = new ObservableCollection<long>();

        WindowCollection.Add(1);
        WindowCollection.Add(2);            
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        WindowCollection.Add(3);
        WindowCollection.Add(4);
    }
}

UserControl

public partial class UserControl1 : UserControl
{
    #region Public Section

    public ObservableCollection<long> UCItems { get; set; }
    public static UserControl1 control;

    #endregion

    public UserControl1()
    {
        InitializeComponent();
        UCItems = new ObservableCollection<long>();            
    }

    #region UCItemsSource Property

    public static readonly DependencyProperty UCItemsSourceProperty = DependencyProperty.Register("UCItemsSource", 
                                                                                                  typeof(IEnumerable), 
                                                                                                  typeof(UserControl1),
                                                                                                  new PropertyMetadata(null, new PropertyChangedCallback(OnUCItemsSourceChanged)));

    public IEnumerable UCItemsSource
    {
        get { return (IEnumerable)GetValue(UCItemsSourceProperty); }
        set { SetValue(UCItemsSourceProperty, value); }
    }

    #endregion

    private static void OnUCItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        control = d as UserControl1;
        var items = e.NewValue as ObservableCollection<long>;

        items.CollectionChanged += new NotifyCollectionChangedEventHandler(CollectionChanged);
        AddItem(control, items);
    }

    private static void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        var items = sender as ObservableCollection<long>;
        control.UCItems.Clear();

        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            AddItem(control, items);
        }
    }

    private static void AddItem(UserControl1 userControl, ObservableCollection<long> collection) 
    {
        if (collection.Count > 0)
        {
            foreach (var item in collection)
            {
                userControl.UCItems.Add(item);
            }
        }
    }
}

該項目在此link可用

Alternative version

此版本更簡單,更正確。 在這里,我們只引用包含集合的UCItemsSource屬性,在這里還用RelativeSource證明了這一點:

UserControl

XAML

<Grid>
    <ItemsControl ItemsSource="{Binding Path=UCItemsSource, 
                                        RelativeSource={RelativeSource Mode=FindAncestor,
                                                                       AncestorType={x:Type UserControl}}}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

Code-behind

public partial class UserControl1 : UserControl
{
    #region Public Section

    public ObservableCollection<long> UCItems { get; set; }

    #endregion

    public UserControl1()
    {
        InitializeComponent();

        UCItems = new ObservableCollection<long>();
    }

    #region UCItemsSource Property

    public static readonly DependencyProperty UCItemsSourceProperty = DependencyProperty.Register("UCItemsSource", 
                                                                                                  typeof(IEnumerable), 
                                                                                                  typeof(UserControl1));                                                                                                      

    public IEnumerable UCItemsSource
    {
        get { return (IEnumerable)GetValue(UCItemsSourceProperty); }
        set { SetValue(UCItemsSourceProperty, value); }
    }

    #endregion
}

嘗試這個

private ObservableCollection<long> _windowCollection 
public ObservableCollection<long> WindowCollection 
{ 
   get { return _windowCollection; }
   set
   {
      _windowCollection = value;
      RaiseOnPropertyChange(() => WindowCollection);
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM