为什么Binding工作不可预测?

时间:2016-05-24 12:27:14

标签: c# .net wpf data-binding binding

我使用两个自定义依赖项属性创建一个控件(让它是listViewEx):SelectedItem,ItemsSource。 此控件派生自ContentControl,并将Content属性设置为ListView实例。

listViewEx有下一个绑定:

  

listViewEx.SelectedItem - > ListView.SelectedItem,   listViewEx.ItemsSource - > ListView.ItemsSource

现在我有一个表单,有两个组合框(box1和box2)和一个listViewEx, 表格有下一个绑定:

  

box1.SelectedItem - > SelectedPerson,   box1.ItemsSource - >人

     

box2.SelectedItem - > SelectedPerson,   box2.ItemsSource - >人

     

listViewEx.SelectedItem - > SelectedPerson,   listViewEx.ItemsSource - >人

form具有有效的DataContext值,其中包含相应的SelectedPerson和Persons属性和值。

现在的问题是:为什么每个绑定工作正常,除了这一个:

  

listViewEx.SelectedItem - > SelectedPerson

如果我更改组合框中的值 - 比listViewEx中的选择更改,直到我更改ListViewEx中的选择,之后组合框工作正常,但listViewEx会丢失每个绑定。我做错了什么?

Problem reproduction video (gif)

listViewEx代码:

public class ListViewEx : ContentControl
{
    ListView list = new ListView();

    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ItemsSource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(ListViewEx), new UIPropertyMetadata(null));


    public object SelectedItem
    {
        get { return (object)GetValue(SelectedItemProperty); }
        set { SetValue(SelectedItemProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SelectedItem.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SelectedItemProperty =
        DependencyProperty.Register("SelectedItem", typeof(object), typeof(ListViewEx), new UIPropertyMetadata(null));

    public ListViewEx()
    {
        Content = list;
        list.SetBinding(ListView.SelectedItemProperty, "SelectedItem");
        list.SetBinding(ListView.ItemsSourceProperty, "ItemsSource");
        list.DataContext = this;
    }
}

表单代码:

public partial class MainWindow : Window
{
    Data data;
    public MainWindow()
    {
        InitializeComponent();
        data = new Data
        {
            Persons = new[] { 
                new Person{ Age=11, Name="Ivan"}, 
                new Person{ Age=10, Name="Petr"}, 
                new Person{ Age=20, Name="Masha"}, 
                new Person{ Age=30, Name="Dasha"}, 
                new Person{ Age=40, Name="Gennadiy"}, 
                new Person{ Age=50, Name="Viktor"}, 
                new Person{ Age=90, Name="Victory!"}, 
            }
        };

        DataContext = data;
    }

    class Data
    {
        public Person[] Persons { get; set; }
        public object SelectedPerson { get; set; }
    }

    class Person
    {
        public int Age { get; set; }
        public string Name { get; set; }
        public override string ToString()
        {
            return Name;
        }
    }
}

表格XAML:

<Window x:Class="DependencyPropertyTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:DependencyPropertyTest"
    Title="MainWindow" Height="350" Width="525">
<StackPanel>
    <ComboBox ItemsSource="{Binding Persons}" SelectedItem="{Binding SelectedPerson}"></ComboBox>
    <ComboBox ItemsSource="{Binding Persons}" SelectedItem="{Binding SelectedPerson}"></ComboBox>
    <local:ListViewEx ItemsSource="{Binding Persons}" SelectedItem="{Binding SelectedPerson}" Height="400"></local:ListViewEx>
</StackPanel>

1 个答案:

答案 0 :(得分:2)

ListViewEx控件的SelectedItem属性应该双向绑定,可以通过编写

<local:ListViewEx SelectedItem="{Binding SelectedPerson, Mode=TwoWay}" ... />

或默认情况下将其声明为双向绑定:

public static readonly DependencyProperty SelectedItemProperty =
    DependencyProperty.Register(
        "SelectedItem",
        typeof(object),
        typeof(ListViewEx),
        new FrameworkPropertyMetadata(
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));