简体   繁体   English

UserControl中的WPF绑定集合属性(xaml)

[英]Wpf binding collection property in UserControl (xaml)

Add collections of buttons in my userControl (Options). 在我的userControl(选项)中添加按钮集合。 In xaml disigner the are displayed. 在xaml disigner中显示。

Output When i run my application: 输出当我运行我的应用程序时:

  • If Options not initialized, then an error XamlObjectWriterException: Property collection "WpfAppUserControl.Buttons"."Options" (null). 如果未初始化Options,则发生错误XamlObjectWriterException:属性集合“ WpfAppUserControl.Buttons”。“ Options”(空)。
  • If Options = new List(), then window without buttons 如果Options = new List(),则窗口不带按钮

MainWindow.xaml MainWindow.xaml

    <Window x:Class="WpfAppUserControl.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfAppUserControl"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="300">
    <Grid>
        <local:Buttons x:Name="Buttons"  
                       VerticalAlignment="Center"
                       HorizontalAlignment="Center" 
                       HorizontalContentAlignment="Center">
            <local:Buttons.Options>
                <Button Content="Agudabi 1" Height="20" Margin="2" />
                <Button Content="Agudabi 2" Height="20" Margin="2" />
                <Button Content="Agudabi 3" Height="20" Margin="2" />
            </local:Buttons.Options>
        </local:Buttons>
    </Grid>
</Window>

Buttons.xaml Buttons.xaml

<UserControl x:Class="WpfAppUserControl.Buttons"
             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" 
             xmlns:local="clr-namespace:WpfAppUserControl"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <WrapPanel x:Name="InternalContainer"  Orientation="Horizontal" HorizontalAlignment="Center"/>
    </Grid>
</UserControl>

Buttons.xaml.cs Buttons.xaml.cs

#region Usings

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

#endregion

namespace WpfAppUserControl
{
    public partial class Buttons : UserControl
    {
        public Buttons()
        {
            //Options = new ObservableCollection<Button>();
            InitializeComponent();
        }

        public ObservableCollection<Button> Options
        {
            get { return (ObservableCollection<Button>) GetValue(OptionsProperty); }
            set { SetValue(OptionsProperty, value); }
        }

        public static readonly DependencyProperty OptionsProperty =
            DependencyProperty.Register(nameof(Options), typeof(ObservableCollection<Button>), typeof(Buttons),
                                        new PropertyMetadata(/*new ObservableCollection<Button>()*/, PropertyChangedCallback));

        private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var obj = d as Buttons;

            foreach (var button in obj.Options)
            {
                obj.InternalContainer.Children.Add(button);
            }
        }
    }
}

Here is an example of what you should actually do. 这是您应实际执行的示例。

Instead of a UserControl with a collection property, use an ItemsControl like this: 代替具有集合属性的UserControl,使用如下的ItemsControl:

<ItemsControl ItemsSource="{Binding Options}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Content="{Binding Name}" Command="{Binding Command}"
                    Height="20" Margin="2"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Then create a view model with a collection of data items with properties for the Button Content and Command: 然后使用数据项集合创建一个视图模型,该数据项具有Button Content和Command属性:

public class ViewModel
{
    public ObservableCollection<Option> Options { get; }
        = new ObservableCollection<Option>();
}

public class Option
{
    public string Name { get; set; }
    public ICommand Command { get; set; }
}

Initialize it like shown below, where the ICommand implementation is ommited for brevity. 如下所示进行初始化,为简洁起见,此处省略了ICommand实现。 Search the web for RelayCommand for a the implementation details. 在Web上搜索RelayCommand以获取实现详细信息。

public MainWindow()
{
    InitializeComponent();

    var vm = new ViewModel();
    vm.Options.Add(new Option { Name = "Agudabi 1" });
    vm.Options.Add(new Option { Name = "Agudabi 2" });
    vm.Options.Add(new Option { Name = "Agudabi 3" });

    DataContext = vm;
}

first initialize OptionsProperty with an empty ObservableCollection: 首先使用一个空的ObservableCollection初始化OptionsProperty

public partial class Buttons : UserControl
{
    public Buttons()
    {
        Options = new ObservableCollection<Button>();

        InitializeComponent();
    }

    public ObservableCollection<Button> Options
    {
        get { return (ObservableCollection<Button>) GetValue(OptionsProperty); }
        set { SetValue(OptionsProperty, value); }
    }

    public static readonly DependencyProperty OptionsProperty =
        DependencyProperty.Register("Options", typeof(ObservableCollection<Button>), typeof(Buttons));    
}

Clemens commented that " Never set the default value of a collection type DP to anything else than null . Otherwise all instances of the UserControl class will operate on the same default collection instance." Clemens评论说:“ 切勿将集合类型DP的默认值设置为null以外的任何其他null 。否则,UserControl类的所有实例都将在同一默认集合实例上运行。” The same is true about any reference type. 任何引用类型都是如此。 So property initialization is done in constructor. 因此,属性初始化是在构造函数中完成的。

you can do without PropertyChangedCallback , because it is possible to display collection more effectively using ItemsControl : 您可以不使用PropertyChangedCallback ,因为可以使用ItemsControl更有效地显示集合:

<UserControl x:Name="myUC" x:Class="WpfAppUserControl.Buttons"
             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" 
             xmlns:local="clr-namespace:WpfAppUserControl"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
  <Grid>
    <ItemsControl ItemsSource="{Binding Path=Options, ElementName=myUC}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel x:Name="InternalContainer"  Orientation="Horizontal" HorizontalAlignment="Center"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
  </Grid>
</UserControl>

note that PropertyChangedCallback is not triggered when you add items to collections because collection property itself hasn't changed, it is the same reference 请注意,将项目添加到集合时不会触发PropertyChangedCallback,因为集合属性本身并未更改,它是相同的引用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM