C# 嵌套数据网格的SelectedValue绑定不';ItemsSource不工作,而ItemsSource不工作

C# 嵌套数据网格的SelectedValue绑定不';ItemsSource不工作,而ItemsSource不工作,c#,wpf,data-binding,datagrid,user-controls,C#,Wpf,Data Binding,Datagrid,User Controls,我有一个DataGrid在一个UserControl中,而这个UserControl又在另一个UserControl中。这是由于项目的其他需要,我不能更改这个嵌套的体系结构。我正在将Person类的列表绑定到此DataGrid。这是一个没有使用VM的简化版本,但在我的实际项目中,我使用的是VM 使用数据网格的MyUserControl: 第二个UserControl包含上述控件: 主窗口 在我的主窗口中,我绑定我的人员列表以及所选人员实例,如下所示: <Grid> <l

我有一个
DataGrid
在一个
UserControl
中,而这个
UserControl又在另一个
UserControl
中。这是由于项目的其他需要,我不能更改这个嵌套的体系结构。我正在将
Person
类的列表绑定到此
DataGrid
。这是一个没有使用
VM
的简化版本,但在我的实际项目中,我使用的是
VM

使用数据网格的My
UserControl
: 第二个
UserControl
包含上述控件: 主窗口 在我的主窗口中,我绑定我的
人员
列表以及
所选人员
实例,如下所示:

<Grid>
    <local:UCDisplay>
        <local:UCDisplay.MyDataGrid>
            <local:UCDataGrid ItemsSource="{Binding People}"
                              SelectedValue="{Binding SelectedPerson, UpdateSourceTrigger=PropertyChanged}"
                              RoutedDataGridDoubleClick="UCDataGrid_RoutedDataGridDoubleClick"/>
        </local:UCDisplay.MyDataGrid>
    </local:UCDisplay>
</Grid>

代码隐藏:

public partial class UCDataGrid : UserControl
{
    public event RoutedEventHandler RoutedDataGridDoubleClick;

    public UCDataGrid()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(object), typeof(UCDataGrid), new PropertyMetadata(null));
    public object ItemsSource
    {
        get { return GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }

    public static readonly DependencyProperty SelectedValueProperty = DependencyProperty.Register("SelectedValue", typeof(object), typeof(UCDataGrid), new PropertyMetadata(null));
    public object SelectedValue
    {
        get { return GetValue(SelectedValueProperty); }
        set { SetValue(SelectedValueProperty, value); }
    }

    private void MyDg_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        RoutedDataGridDoubleClick?.Invoke(this, new RoutedEventArgs());
    }
}
public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    private List<Person> people;
    public List<Person> People
    {
        get => people;
        set => SetField(ref people, value);
    }

    private Person selectedPerson;
    public Person SelectedPerson
    {
        get => selectedPerson;
        set => SetField(ref selectedPerson, value);
    }

    public MainWindow()
    {
        InitializeComponent();
        People = GetPeople();
        DataContext = this;
    }

    private void UCDataGrid_RoutedDataGridDoubleClick(object sender, RoutedEventArgs e)
    {

    }

    private List<Person> GetPeople()
    {
        return new List<Person>
        {
            new Person() { Name = "A" },
            new Person() { Name = "B" },
            new Person() { Name = "C" }
        };
    }

    public class Person
    {
        public string Name { get; set; }
    }
}
public分部类主窗口:窗口,INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
受保护的无效OnPropertyChanged(字符串propertyName)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
受保护的布尔设置字段(参考T字段,T值,[CallerMemberName]字符串propertyName=null)
{
if(EqualityComparer.Default.Equals(字段,值))返回false;
字段=值;
OnPropertyChanged(propertyName);
返回true;
}
私人名单;
公众人物名单
{
get=>人;
set=>SetField(参考人员,值);
}
私人选择的人;
公众人士
{
get=>selectedPerson;
set=>SetField(参考selectedPerson,值);
}
公共主窗口()
{
初始化组件();
People=GetPeople();
DataContext=this;
}
私有void UCDataGrid\u路由数据网格双击(对象发送方,路由数据目标e)
{
}
私有列表GetPeople()
{
返回新列表
{
新人(){Name=“A”},
新人(){Name=“B”},
新人(){Name=“C”}
};
}
公共阶层人士
{
公共字符串名称{get;set;}
}
}
同样,在现实中,我使用的是
VM
,这只是为了让事情变得简单

现在,当我运行此命令时,我可以很好地显示列表内容。但是,当我双击我的
DataGrid
中的一个项目时,在我的主窗口中相应的“代码隐藏”中,
SelectedPerson
保持
null
,尽管其绑定与
人员
列表相同。我通过在主代码后面使用断点来确认这一点:

但是如果我调试并看到最里面的
UserControl
的代码后面的值,您会看到那里的
SelectedValue
具有正确的selecteditems值


那么我做错了什么?为什么我不能绑定
SelectedValue
,虽然我的绑定方式与
ItemsSource
完全相同,但后者可以工作?

SelectedValue
应该与
SelectedValuePath
一起使用。您应该改用
SelectedItem

除此之外,您还缺少一个双向的
绑定。通过双向显式声明
SelectedItem
绑定

<DataGrid x:Name="MyDg"
    ItemsSource="{Binding ItemsSource,
        RelativeSource={RelativeSource AncestorType=UserControl}}"
    SelectedItem="{Binding SelectedItem,
        RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay}"/>

另外请注意,在所有绑定中设置
UpdateSourceTrigger=PropertyChanged
是毫无意义的。

谢谢!不知何故,我认为双向绑定是默认的,如果未指定,这就是绑定。我想我错了。
<Grid>
    <local:UCDisplay>
        <local:UCDisplay.MyDataGrid>
            <local:UCDataGrid ItemsSource="{Binding People}"
                              SelectedValue="{Binding SelectedPerson, UpdateSourceTrigger=PropertyChanged}"
                              RoutedDataGridDoubleClick="UCDataGrid_RoutedDataGridDoubleClick"/>
        </local:UCDisplay.MyDataGrid>
    </local:UCDisplay>
</Grid>
public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    private List<Person> people;
    public List<Person> People
    {
        get => people;
        set => SetField(ref people, value);
    }

    private Person selectedPerson;
    public Person SelectedPerson
    {
        get => selectedPerson;
        set => SetField(ref selectedPerson, value);
    }

    public MainWindow()
    {
        InitializeComponent();
        People = GetPeople();
        DataContext = this;
    }

    private void UCDataGrid_RoutedDataGridDoubleClick(object sender, RoutedEventArgs e)
    {

    }

    private List<Person> GetPeople()
    {
        return new List<Person>
        {
            new Person() { Name = "A" },
            new Person() { Name = "B" },
            new Person() { Name = "C" }
        };
    }

    public class Person
    {
        public string Name { get; set; }
    }
}
<DataGrid x:Name="MyDg"
    ItemsSource="{Binding ItemsSource,
        RelativeSource={RelativeSource AncestorType=UserControl}}"
    SelectedItem="{Binding SelectedItem,
        RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay}"/>
public static readonly DependencyProperty SelectedItemProperty =
    DependencyProperty.Register(
        nameof(SelectedItem), typeof(object), typeof(UCDataGrid),
        new FrameworkPropertyMetadata(
            null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

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