【问题标题】:Why does my Dependency Property send null to my view model?为什么我的依赖属性将 null 发送到我的视图模型?
【发布时间】:2016-08-15 15:32:39
【问题描述】:

我遇到了一个难以诊断的问题。

我创建了一个自定义 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; }
}

【问题讨论】:

  • Visual Studio 的输出窗口中是否有任何绑定错误消息? IList 可能无法分配给IEnumerable&lt;TestModel&gt;
  • 输出窗口中没有出现错误信息,绑定或其他。此外,如果我将视图模型中的TestModelsSelectedTestModels 的类型更改为IList&lt;TestModel&gt;,我仍然会收到一个空值发送。

标签: c# wpf xaml data-binding datagrid


【解决方案1】:

您正在交替使用非泛型 IList 和 IList。你有几个选择。

在您的视图模型中,您可以将属性和字段更改为 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);
}

【讨论】:

  • 抱歉,看起来没有任何作用。视图模型仍在接收 null。
  • 我认为这不是您的绑定,我认为您的 IList 在 CustomControl 中为空。尝试在 SelectionChanged 事件的末尾放置一个断点和以下代码,我敢打赌 SelectedItemsList 也为空。 var test = SelectedItemsList;
  • 你是对的。如果我在调用this.SelectedItemsList = this.SelectedItems 后添加该行,SelectedItemsList 仍然为空,即使SelectedItems 有效并且其中包含数据。我将如何解决这个问题?
  • @MageXy,我必须创建一个新项目才能看到它,但我相信它现在正在运行。查看编辑。
  • 谢谢!我不敢相信修复如此简单。我想知道为什么我没有收到任何错误......肯定应该抛出类型转换错误吗?好吧,无论如何,它现在可以工作了。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-24
相关资源
最近更新 更多