【问题标题】:MVVM OnPropertyChanged not changing view when using assignment operator (PropertyChanged becomes null)MVVM OnPropertyChanged 在使用赋值运算符时不改变视图(PropertyChanged 变为空)
【发布时间】:2015-05-28 08:25:20
【问题描述】:

我正在尝试创建一个撤消/重做系统。当前,当用户执行某项操作时,原始对象和新对象将按“操作”复制到列表中。如果我按下撤消按钮,我想再次将原始值分配给新值。

我已经能够在列表中同时获取新对象和原始对象,但是使用我所做的撤消再次分配旧对象时出现错误。它在包含所有可以更改但不在视图中更新的主列表中更新。

undo方法是这样的:

for (int t = 0; t < mainData.GroupModelList.Count; ++t)
{
    if (mainData.GroupModelList[t].Name == commandList.ElementAt(position).groupModelNew.Name)
    {
        mainData.GroupModelList[t] = new ViewModels.GroupViewModel(commandList.ElementAt(position).groupModelOrig);
        break;
    }
}

这会调用 GroupViewModel 的构造函数:

public GroupViewModel(GroupViewModel selectedGroup)
{ 
    groupModel = new GroupModel();

    // values are assigned from the selectedGroup here (which is the original object in the UndoRedo part)
    // ...

    OnPropertyChanged(null);
 }

这是 OnPropertyChanged 方法:

private void OnPropertyChanged(string Property)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(Property));
    }
} 

我在某处读到,在 PropertyChangedEventArgs 使用“null”会使所有内容都更新,所以这就是我尝试过的,但它不起作用。
在更多断点之后,我注意到PropertyChanged 在调用新构造函数时为空,这可能是问题所在。不过,它确实可以在没有撤消/重做的情况下工作。 (当简单地改变对象使用文本框或类似的值时)

我还读到我应该将 DataContext 指向对象本身,但这似乎是不可能的,因为该对象没有 DataContext 属性。

编辑:人们告诉我应该使用 ObservableCollection。我已经在使用它了。像这样:(这是 View 可以访问的列表)

private ObservableCollection<GroupViewModel> groupModelList = new ObservableCollection<GroupViewModel>();
public ObservableCollection<GroupViewModel> GroupModelList
{
    get { return groupModelList; }
}

编辑:这是绑定到视图的方式:
首先是 XAML 中的绑定

<Window.Resources>
    <vm:MainViewModel x:Key="MainViewModel" />
</Window.Resources>

MainViewModel 拥有一个 MainData 类型的对象,并且在该类内部有一个 ObservableCollection&lt;GroupViewModel&gt;
例如,这是将列表中选定项目的名称绑定到视图中的文本框的代码:(第一行是显示 GroupViewModel 列表中所有项目的列表框,第二行是我想给出的文本框一个例子)

<ListBox DisplayMemberPath="Name" Height="412" HorizontalAlignment="Left" ItemsSource="{Binding Source={StaticResource MainViewModel}, Path=mainData.FilteredGroupModelList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="10,44,0,0" Name="lbFoundItems" SelectedItem="{Binding Source={StaticResource MainViewModel}, Path=SelectedGroup, Mode=OneWayToSource}" VerticalAlignment="Top" Width="250" SelectionMode="Single" />

<ComboBox Height="23" HorizontalAlignment="Left" ItemsSource="{Binding ElementName=lbFoundItems, Path=SelectedItem.Types, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="436,378,0,0" Name="cmbTypes" SelectedItem="{Binding Source={StaticResource MainViewModel}, Path=SelectedType, Mode=OneWayToSource}" VerticalAlignment="Top" Width="180" />

这也是SelectedGroup 变量,它包含对列表框中所选项目的引用:

private GroupViewModel selectedGroup;
public GroupViewModel SelectedGroup
{
    get { return selectedGroup; }
    set
    {
        selectedGroup = value;
        OnPropertyChanged("SelectedGroup");
    }
}

【问题讨论】:

  • 在哪里分配 GroupViewModel 的新实例?持有该实例的对象/视图模型需要调用 PropertyChangedEvent
  • 在第一段代码中,您可以看到我再次将旧对象分配给新对象。我搜索对象的主列表,然后将其分配给new。像这样:mainData.GroupModelList[t] = new ViewModels.GroupViewModel(commandList.ElementAt(position).groupModelOrig);。此外,正如您在第二段代码中看到的那样,在 viewModel 的构造函数中调用 PropertyChanged

标签: c# wpf mvvm


【解决方案1】:

这里应该更新的“所有内容”是什么?想一想,这并不神奇:绑定到对象实例的 UI 元素订阅了PropertyChanged,这就是它们在触发时更新的原因。

统一更新: 我不认为我可以在这里获得完整的图片,不清楚您要更新什么以及您正在使用哪些类。您的示例包含 forifbreak,但没有 XAML!这在讨论 WPF 机制时真的很重要吗?.. 我如何确定该错误不存在? 分解任务。毫无悔意地分解它。无论您的业务如何,都可以创建一个小型项目,收集项目并仅使用 wpf。当您这样做时,您将有 70% 的机会自己找到根本原因,20% 的机会通过 google 成功,而提出问题将帮助您解决剩下的 10% 的情况。

【讨论】:

  • 我在 GroupModelList 中使用ObservableCollection
【解决方案2】:

问题是您正在通过使用这行代码创建一个新对象来更改列表控件中项目的DataContext...

mainData.GroupModelList[t] = new ViewModels.GroupViewModel(commandList.ElementAt(position).groupModelOrig);

需要通知绑定到mainData.GroupModelListItemsControl 集合已更改,而不是通知单个ViewModel 对象已更新。

确保GroupModelListObservableCollection&lt;T&gt;,因为它实现了INotifyCollectionChanged

编辑:“你有任何关于我应该如何做的参考吗?”

它被称为备忘录模式。将它与 Stack 结合起来以实现完整的应用程序撤消/重做功能。 Memento Pattern

【讨论】:

  • 有什么帮助吗?
  • 我已经在使用它了,我会把它添加到我原来的问题中
  • 你是如何定义BindingGroupModelList 的?你也可以发一下吗?
  • 我用那个编辑了我的问题(我想这就是你想看到的)
  • 你也可以发布SelectedGroup的定义吗?您似乎没有在撤消代码中的任何地方使用它,但已将其绑定到 TextBox 以在 TextBox 本地操作 Name 属性(您需要设置 UpdateSourceTrigger=PropertyChanged 以将 btw 更新为 @987654337 @ 默认使用LostFocus)。如果您在通过OneWayToSource Binding 进行分配时没有创建副本对象,那么您实际上只是在尝试覆盖原始对象的值并且您没有保存任何原始副本对象。
【解决方案3】:

尝试 RaisePropertyChanged();在 peoperty setter 中使用时不需要参数

【讨论】:

    猜你喜欢
    • 2020-02-18
    • 1970-01-01
    • 2015-02-08
    • 1970-01-01
    • 2014-10-11
    • 2017-12-12
    • 2014-04-24
    • 2013-03-17
    • 1970-01-01
    相关资源
    最近更新 更多