为什么我的Dependency Property会向我的视图模型发送null?

时间:2016-08-15 15:32:40

标签: c# wpf xaml data-binding datagrid

我遇到了一个我在诊断时遇到问题的问题。

我已经创建了一个自定义DataGrid对象(详见Sandesh的回答here),以便能够绑定到数据网格的各个选定项目。但是,即使看起来DependecyProperty本身在选择更改时获得了正确的值,视图模型也似乎永远不会收到更新的值(它会变为null)。

自定义DataGrid类:

class CustomDataGrid : DataGrid
{
    public CustomDataGrid()
    {
        this.SelectionChanged += CustomDataGrid_SelectionChanged;
    }

    void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        this.SelectedItemsList = this.SelectedItems;
    }
    #region SelectedItemsList

    // In the setter, the value is a valid List with the correct elements.
    // For some reason it doesn't seem to be passed on to the view model. 
    public IList SelectedItemsList
    {
        get { return (IList)GetValue(SelectedItemsListProperty); }
        set { SetValue(SelectedItemsListProperty, value); }
    }

    public static readonly DependencyProperty SelectedItemsListProperty =
            DependencyProperty.Register("SelectedItemsList", typeof(IList), typeof(CustomDataGrid), new PropertyMetadata(OnSelectedItemsListChanged));

    private static void OnSelectedItemsListChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Test");
    }

    #endregion
}

XAML文件:

<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Test"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:TestViewModel />
    </Window.DataContext>
    <Grid>
        <local:CustomDataGrid AutoGenerateColumns="True"
                              SelectionMode="Extended"
                              SelectionUnit="FullRow"
                              CanUserAddRows="False"
                              CanUserDeleteRows="False"
                              CanUserResizeRows="False"
                              ItemsSource="{Binding TestModels}"
                              SelectedItemsList="{Binding Path=SelectedTestModels, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />    
    </Grid>
</Window>

查看型号:

class TestViewModel : INotifyPropertyChanged
{
    public TestViewModel()
    {
        TestModels = new List<TestModel>
        {
            new TestModel { Name = "Test 1", ID = 1 },
            new TestModel { Name = "Test 2", ID = 2 },
            new TestModel { Name = "Test 3", ID = 3 },
        };
    }

    private IEnumerable<TestModel> _testModels;

    public IEnumerable<TestModel> TestModels
    {
        get { return _testModels; }
        set
        {
            _testModels = value;
            OnPropertyChanged();
        }
    }

    private IEnumerable<TestModel> _selectedTestModels;

    public IEnumerable<TestModel> SelectedTestModels
    {
        get { return _selectedTestModels; }
        set
        {
            // Right here I would expect value to have a non-null value... but it's always null
            _selectedTestModels = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var propChanged = PropertyChanged;
        if (propChanged != null)
            propChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

TestModel类(非常简单的POCO):

class TestModel
{
    public string Name { get; set; }
    public int ID { get; set; }
}

1 个答案:

答案 0 :(得分:1)

您可以互换使用非通用IList和IList。你有几个选择。

在您的viewmodel中,您可以将属性和字段更改为IList。

private IList _selectedTestModels;

public IList SelectedTestModels
{
    get { return _selectedTestModels; }
    set
    {
        _selectedTestModels = value;
        OnPropertyChanged();
    }
}

或者在CustomControl中。

public static readonly DependencyProperty SelectedItemsListProperty = DependencyProperty.Register("SelectedItemsList", typeof(IList<TestModel>), typeof(CustomDataGrid));

public IList<TestModel> SelectedItemsList
{
    get { return (IList<TestModel>)GetValue(SelectedItemsListProperty); }
    set { SetValue(SelectedItemsListProperty, value); }
}

void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    SetCurrentValue(SelectedItemsListProperty, SelectedItems.OfType<TestModel>().ToList());
}

作为旁注,我也相信这段代码可能会破坏你的约束力。

void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    this.SelectedItemsList = this.SelectedItems;
}

尝试使用SetCurrentValue来维护您的绑定。

void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    SetCurrentValue(SelectedItemsListProperty, SelectedItems);
}