WPF 自定义控件 : DependencyProperty TwoWay Binding

标签 wpf custom-controls dependency-properties

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

<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 和一个按钮的处理程序 (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(绑定(bind)到文章)。 这是我使用 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。我在这里做错了什么吗?这是预期的行为吗?如果是,那么这样做的不同方式是什么: 创建一个包含列表和按钮的自定义控件,按钮的处理程序将在列表中添加对象。

最佳答案

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

当您设置双向绑定(bind)并且目标值无法转换回源类型(即 IEnumerable<object> -> ObservableCollection<Article> )时,源属性(此处为文章)将收到一个空值,它将然后通过绑定(bind)推回目标属性(此处为 ListSource)。

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

一般来说,对集合使用双向绑定(bind)是个坏主意。不必在每次要进行更改时都复制和替换集合实例,只需在一个实例中添加和删除项即可。由于该实例在 (OneWay) 绑定(bind)的两侧是同一个集合,更新将显示在两侧,如果您使用的是 ObservableCollection,您还可以在任一侧获得更改通知。

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

关于WPF 自定义控件 : DependencyProperty TwoWay Binding,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5682217/

相关文章:

c++ - 有什么方法可以在 x < 8 的 Windows x 上从 native C++ 应用程序使用 XAML 和 WPF?

c# - 考虑到透明度,如何检索与其他控件重叠的 WPF 控件的可见区域?

C# 创建自定义控件

c# - 如何在更改 DependencyProperty 后调用方法

c# - 附加属性回调不适用于 wpf VS2012 中的默认值

c# - 如何在 SharpDevelop 4.2 中启动一个国际化的 WPF 项目?

c# - WPF 验证规则阻止在文本框中输入小数点?

.net - 设置默认样式键的方法之间的差异

wpf - MVVM模式中的TypeInitializationException

c# - 即时依赖属性