【问题标题】:MVVM WPF DataGrid SelectedItem via binding fires OnPropertyChanged twiceMVVM WPF DataGrid SelectedItem 通过绑定触发 OnPropertyChanged 两次
【发布时间】:2012-06-24 14:27:49
【问题描述】:

我花了好几个小时试图解决下面描述的问题:

我在我的 MVVM WPF 应用程序中定义了一个 DataGrid,精简后的 XAML 代码如下所示:

<DataGrid AutoGenerateColumns="False" Name="dgdSomeDataGrid" SelectedItem="{Binding SelectedSomeItem, Mode=TwoWay}" ItemsSource="{Binding SomeItemCollection}">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Path=Id}" Header="ID" />
        <DataGridTextColumn Header="Titel" Binding="{Binding Path=Title}" />
        <DataGridTextColumn Header="Status" Binding="{Binding Path=State}" />
    </DataGrid.Columns>
</DataGrid>

在我关联的 ViewModel 中,我有一个相应的属性,例如:

public WorkItemForUi SelectedSomeItem
{
    get
    {
        return SomeObject.SelectedSomeItem;
    }
    set
    {
        SomeObject.SelectedSomeItem = value;
        OnPropertyChanged( "SelectedSomeItem" );
    }
}

在我的控制器中,我有以下内容:

private void MainWindowViewModelPropertyChanged( object sender, PropertyChangedEventArgs e )
{
    if ( e.PropertyName == "SelectedSomeItem" )
    {
        UpdateSelectedSomeItem();
    }
}

我通常想做的是从DataGrid 中检索所选项目,从外部数据存储(在本例中为 TFS)获取有关该项目的更多信息,并在 TextBox 中显示这些额外信息。

所有这些都已按预期工作,但问题是 MainWindowViewModelPropertyChanged 方法被调用了两次,而不是一次

SelectedItem 属性设置为发生两次可能是设计使然,但我不太确定,因为我发现的很多信息有点矛盾(有时也不太清楚是指 Windows 窗体还是 WPF)。

我看到了一些建议,其中为 DataGrid 定义了 SelectionChanged 事件处理程序并使用了 IsSelected 属性,但据我所知,由于我的数据绑定,这不应该是必需的。

更新 作为 MainWindowController 的一部分,有一个 Initialize 方法引用 MainWindowViewModelPropertyChanged 处理程序。

    public void Initialize( string tfsProjectCollection )
    {
        InitializeCommands();
        InitializeViewModel();
        AddWeakEventListener( m_MainWindowViewModel, MainWindowViewModelPropertyChanged );
    }

任何想法可能是我的问题的原因?

【问题讨论】:

  • MainWindowViewModelPropertyChanged() 每次在 ViewModel 中用于 INotifyPropertyChanged 实现的 any 属性发生更改时都会被调用。两个调用中是 e.PropertyName == "SelectedSomeItem" 还是 e.PropertyName 具有不同的值?
  • 您是否在UpdateSelectedSomeItem(); 之后尝试过e.Handled = true,以防由于某种原因同一事件发生两次?
  • @JensH:两者都是一样的(“SelectedSomeItem”)。
  • @Scroog1:在 MainWindowViewModelPropertyChanged 方法中,“e”的类型为“PropertyChangedEventArgs”并且没有“Handled”属性...?
  • SelectedSomeItem.set 是否也被调用了两次?添加条件if (SomeObject.SelectedSomeItem != value) { ... } 是否有帮助(因为这是INotifyPropertyChanged 的典型模式)?

标签: wpf binding mvvm datagrid selecteditem


【解决方案1】:

你的SomeObject.SelectedSomeItem setter 是否也加注OnPropertyChanged( "SelectedSomeItem" );SomeObject 的类型是什么?为什么SomeObject 还需要SelectedSomeItem 属性?

还请在您订阅MainWindowViewModelPropertyChanged 的地方发布一些代码。

selecteditem 的行为我从来没有遇到过问题,但公平地说,我不需要订阅 INotifyPropertyChanged 来获取此信息。我认为你也不需要那个。视图模型之间有更好的通信方式

编辑:这可行,但我不知道 SomeObject 在您的代码中是什么。

private WorkItemForUi _selected;
public WorkItemForUi SelectedSomeItem
{
get
{
    return this._selectedSomeItem;
}
set
{
    this._selectedSomeItem = value;
    OnPropertyChanged( "SelectedSomeItem" );
}
}

【讨论】:

  • SomeObject 是一个手工制作的对象,其中包含在 UI 上显示所需的属性。也许我走错了方向,但是我的 DataGrid 需要一个项目集合,并且集合中其他项目的类型必须是 SelectedItem。对于这个 SelectedItem,我会为绑定到 DataGrid 的集合中的所有项目检索我不想提前检索的其他数据。
【解决方案2】:

好的,在花了一些时间之后,我们发现问题出在ApplicationController 类中。

构造函数调用了该类中的Initialize方法,同一个类中的Run方法也调用了这个方法。

Initialize 方法中调用了主窗口视图模型的“Initialize”方法,其中添加了一个事件监听器:

[...]
AddWeakEventListener( m_MainWindowViewModel, MainWindowViewModelPropertyChanged );
[...]

ApplicationController类的构造函数中移除对Initialize方法的调用解决了这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-12
    • 2021-03-01
    • 2016-10-22
    • 2011-12-11
    • 2015-08-04
    • 1970-01-01
    相关资源
    最近更新 更多