为什么我的依赖属性将null发送给我的视图模型?

问题描述:

我遇到了一个问题,我在诊断时遇到了一些麻烦。为什么我的依赖属性将null发送给我的视图模型?

我已经创建了一个自定义的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; } 
} 
+0

在Visual Studio的输出窗口中是否存在任何绑定错误消息? 'IList'可能不能从'IEnumerable '分配。 – Clemens

+0

没有出现在输出窗口中的错误消息,绑定或其他。此外,如果我将视图模型中'TestModels'和'SelectedTestModels'的类型更改为'IList ',我仍会得到一个空值。 –

您可以交替使用非通用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); 
} 
+0

对不起,它看起来并没有做任何事情。视图模型仍然接收null。 –

+0

我不认为这是你的绑定,我认为你的IList在CustomControl中为null。尝试在你的SelectionChanged事件结束时放置一个断点和下面的代码,我打赌SelectedItemsList也是空的。 var test = SelectedItemsList; –

+0

你是对的。如果在执行'this.SelectedItemsList = this.SelectedItems'调用之后添加该行,'SelectedItemsList'仍然为null,即使'SelectedItems'有效且包含数据。我将如何去解决这个问题? –