【问题标题】:WPF Custom Control: DependencyProperty TwoWay BindingWPF 自定义控件:DependencyProperty TwoWay 绑定
【发布时间】:2011-08-06 15:15:15
【问题描述】:

我有这个自定义用户控件,它有一个列表和一个按钮:

<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}" HorizontalAlignment="Right" Width="174" />
        <Button Name="ButtonAdd" Content="Add" HorizontalAlignment="Left" Width="101" />
    </Grid>
</UserControl>

后面的代码有一个 IEnumerable 类型的 DependencyProperty 和一个用于 Button 的处理程序(OnAdd):

public partial class CustomList : UserControl
{
    public CustomList( )
    {
        InitializeComponent( );
    ButtonAdd.Click += new RoutedEventHandler( OnAdd );
    }

private void OnAdd( object sender, EventArgs e )
{
    IList<object> tmpList = this.ListSource.ToList( );
    Article tmpArticle = new Article( );
    tmpArticle .Name = "g";
    tmpList.Add(tmpArticle );
    ListSource = (IEnumerable<object>) tmpList;
}

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

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

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

在按钮处理程序中,我尝试将文章添加到 ListSource(绑定到文章)。 这是我使用 UserControl(CustomList) 的窗口:

<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, Mode=TwoWay}" Margin="80,0,0,0" />
    </Grid>
</Window>

当我单击按钮时,文章变为空,而不是在文章集合中添加文章。并且 ListSource 属性也变为 null。我在这里做错了吗?这是预期的行为吗?如果是,那么这样做的不同方式是什么: 创建一个包含 List 和 Button 的自定义控件,并且该按钮的处理程序将在 List 中添加对象。

【问题讨论】:

    标签: wpf custom-controls dependency-properties


    【解决方案1】:

    这里有很多问题,但导致您的问题的主要原因是您尝试使用 TwoWay Binding 的属性之间可能存在类型不匹配。您没有列出您的 Articles 属性的代码,但我认为它可能类似于 IEnumerable&lt;Article&gt;ObservableCollection&lt;Article&gt; 而不是您的 ListSource 属性的 IEnumerable&lt;object&gt;

    当你设置了两种方式绑定并且目标值不能被转换回源类型(即IEnumerable&lt;object&gt; -> ObservableCollection&lt;Article&gt;)时,源属性(这里的文章)将收到一个空值,这将然后通过 Binding 推送回目标属性(此处为 ListSource)。

    您可以更改任一侧的类型,但如果您将它们与双向绑定一起使用,则类型应该匹配。

    一般来说,将 TwoWay 绑定与集合一起使用是个坏主意。无需在每次要进行更改时复制和替换集合实例,只需在一个实例中添加和删除项目即可。由于该实例是 (OneWay) Binding 两侧的同一个集合,因此更新将显示在两侧,如果您使用的是 ObservableCollection,您还可以在任一侧收到更改通知。

    您还应该删除 OnValueChanged 代码,因为它只是将属性重置为刚刚在属性上设置的值。

    【讨论】:

    • 其实你是对的,我的 Articles Collection 是 Articles 的 ObservableCollection。现在,如果理解正确,我的 ListSource 属性必须是 ObservableCollection 类型,对吧?不过,在这种情况下,我必须明确声明我的 ListSource 属性是文章的 ObservableCollection。如果我想将我的 UserControl 与不同类型的 ObservableCollections(即 ObservableCollection of Persons)一起使用,这可能是一个问题。如果我错了,您认为您可以提供一个示例,说明什么是更好的方法?
    猜你喜欢
    • 1970-01-01
    • 2013-01-20
    • 1970-01-01
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-03
    • 2019-07-27
    相关资源
    最近更新 更多