Привязка SelectedValue вложенного DataGrid не работает, в то время как ItemsSource работает - PullRequest
0 голосов
/ 14 июля 2020

У меня есть DataGrid внутри UserControl, который, в свою очередь, находится внутри другого UserControl. Это связано с другими потребностями проекта, и я не могу изменить эту вложенную архитектуру. Я привязываю список класса Person к этому DataGrid. Это упрощенная версия без использования VM, но в моем реальном проекте я использую VM.

My UserControl с DataGrid:

<Grid>
    <DataGrid x:Name="MyDg"
        ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource AncestorType=local:UCDataGrid}, UpdateSourceTrigger=PropertyChanged}"
        MouseDoubleClick="MyDg_MouseDoubleClick"
        SelectedValue="{Binding SelectedValue, RelativeSource={RelativeSource AncestorType=local:UCDataGrid}, UpdateSourceTrigger=PropertyChanged}"/>
</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());
    }
}

2-й UserControl, который содержит указанный выше элемент управления:

<Grid>
    <ContentControl Content="{Binding MyDataGrid, ElementName=ucDisplay}"/>
</Grid>

ucDisplay - это просто значение свойства Name из этого UserControl.

Код позади:

Здесь ничего особенного.

public partial class UCDisplay : UserControl
{
    public UCDisplay()
    {
        InitializeComponent();
    }

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

Главное окно

В моем Главное окно, я привязываю свой список People, а также экземпляр SelectedPerson, например:

<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; }
    }
}

Опять же, на самом деле я использую VM, это только для простоты.

Теперь, когда я запускаю это, я могу нормально отображать содержимое моего списка. Но когда я дважды щелкаю элемент в моем DataGrid, в соответствующем коде в моем главном окне позади, SelectedPerson остается null, хотя его привязка идентична списку People. Я подтверждаю это, используя точку останова в основном коде позади:

enter image description here

But if I debug and see the value in the code behind of my innermost UserControl, you see that the SelectedValue there has the correct selected items value.

введите описание изображения здесь

Так что я здесь делаю не так? Почему я не могу привязать SelectedValue, хотя я делаю это точно так же, как привязка ItemsSource, но последнее работает?

1 Ответ

1 голос
/ 14 июля 2020

SelectedValue предполагается использовать вместе с SelectedValuePath. Вместо этого вы должны использовать SelectedItem.

Кроме того, вам не хватает привязки TwoWay. Либо явно объявите SelectedItem Binding TwoWay

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

, либо зарегистрируйте свойство для привязки 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); }
}

Также обратите внимание, что установка UpdateSourceTrigger=PropertyChanged бессмысленна во всех ваших привязках .

...