WPF自定义控件:依赖属性双向绑定

3

我有一个自定义的用户控件,其中包含列表和按钮:

<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(它绑定到Articles)。这是我使用自定义用户控件(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>

当我点击按钮时,文章会变成null,而不是将文章添加到文章集合中。ListSource属性也变为null。我在这里做错了什么吗?这是预期的行为吗?如果是,有没有其他不同的方法可以实现: 创建一个自定义控件,该控件将具有列表和按钮,按钮的处理程序将向列表中添加对象。
1个回答

5
这里有很多问题,但是导致你的问题的主要原因可能是,你试图在类型不匹配的属性上使用双向绑定。您没有列出Articles属性的代码,但我假设它可能类似于“IEnumerable
”或“ObservableCollection
”,而不是您的ListSource属性中的“IEnumerable”。
当您设置双向绑定并且目标值无法转换回源类型(即“IEnumerable”->“ObservableCollection
”)时,源属性(这里是Articles)将接收一个空值,然后通过绑定推送回目标属性(这里是ListSource)。
您可以更改两侧的类型,但如果您将它们与双向绑定一起使用,则应匹配类型。
通常,在集合中使用双向绑定是一个坏主意。不要每次想要进行更改时都复制和替换集合实例,只需从一个实例添加和删除项目。由于该实例是(单向)绑定的两侧相同的集合,因此更新将在两侧显示。如果您使用ObservableCollection,则还可以在任一侧获得更改通知。
您还应该摆脱OnValueChanged代码,因为它只是将属性重置为刚刚在属性上设置的值。

实际上,你是对的,我的Articles Collection是一个Article的ObservableCollection。现在,如果我理解正确的话,我的ListSource属性必须是ObservableCollection类型,对吗?但是,在这种情况下,我必须明确声明我的ListSource属性是一个Article的ObservableCollection,如果我想要将我的UserControl与不同类型的ObservableCollections(例如Person的ObservableCollection)一起使用,那可能会有问题。如果我错了,你能否提供一个更好的方法的示例呢? - Aris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接