Wpf MVVM实现的问题:对所选项目的更改将发布到列表,不希望这样

Wpf MVVM实现的问题:对所选项目的更改将发布到列表,不希望这样,wpf,data-binding,mvvm,mvvm-light,Wpf,Data Binding,Mvvm,Mvvm Light,所以我遇到了这个问题,希望你能帮我解决 我正在使用MVVM Light作为框架编写一个WPF应用程序。在这种情况下,我有一个项目列表,SelectedItem绑定到用户可以编辑项目的详细信息视图。在这种情况下,有一个保存按钮用于显式保存数据 我的问题是,当用户编辑数据时,更改会立即显示在列表中。如果用户取消,则会重置所选项目,但仍会更改。如何防止更改传播 我试图实现一个克隆实现,但一旦我实现了,MVVM Light的消息传递系统就会陷入循环,导致StackOverflowException,因为

所以我遇到了这个问题,希望你能帮我解决

我正在使用MVVM Light作为框架编写一个WPF应用程序。在这种情况下,我有一个项目列表,SelectedItem绑定到用户可以编辑项目的详细信息视图。在这种情况下,有一个保存按钮用于显式保存数据

我的问题是,当用户编辑数据时,更改会立即显示在列表中。如果用户取消,则会重置所选项目,但仍会更改。如何防止更改传播

我试图实现一个克隆实现,但一旦我实现了,MVVM Light的消息传递系统就会陷入循环,导致StackOverflowException,因为我一直在克隆对象。同样,克隆实现也很难看

你知道我该怎么做吗

编辑:

列表视图的基本XAML:

    <DataGrid DataContext="{Binding SubJobTypes}"
              ItemsSource="{Binding}"
              SelectedItem="{Binding ElementName=Root, Path=DataContext.SelectedSubJobType, Mode=TwoWay}">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Name}"/>
        </DataGrid.Columns>
    </DataGrid>

编辑视图的基本XAML:

   <StackPanel>
        <StackPanel>
            <StackPanel Orientation="Horizontal" DataContext="{Binding Path=CurrentSubJobType}">
                <TextBlock Text="Name"/>
                <TextBox Text="{Binding Path=Name, Mode=TwoWay}" Width="150"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <Button Content="{Binding Path=SubmitCommandText, FallbackValue=Submit}" >
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding Path=SaveSubJobTypeCommand}"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
                <Button Content="Cancel" >
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding Path=CancelCommand}"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
                <Button Content="Delete">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding Path=DeleteCommand}"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
            </StackPanel>
        </StackPanel>
    </StackPanel>


ViewModels是标准的,不必麻烦发布,我认为您可能希望禁用“双向”数据绑定,并且仅在用户按下提交按钮时将数据写入模型。

在主视图和详细视图中,您似乎(双向)绑定到ViewModel中的同一对象

可能的替代方案包括:

  • 创建对象的副本
  • 在ViewModel中创建其他参数,例如“EditName”,并将其绑定到编辑视图而不是名称。它们最初将设置为与Name属性相同的值。保存时,您可以设置此.Name=this.EditName。取消时,您将设置this.EditName=this.Name

您应该有两个视图模型,一个用于列表项,另一个用于详细视图,而不是禁用绑定机制。一旦选择了一个项目,列表视图模型就会发送一条属性更改消息。然后,详图视图模型加载项目数据,或克隆模型并使用数据初始化自身。现在,详图视图模型可以更改其模型的本地实例

完成后,数据将保存到数据库中,详图视图模型将发送一条消息,说明项目已更改。列表视图模型现在接收消息,可以使用该模型更改其项目视图模型,也可以从数据库重新加载项目模型,然后更新项目视图模型


通过这种方式,您不必手动将值写入模型,如果只克隆模型,则不应在消息传递方面遇到任何问题。

-1因为这不符合mvvm让绑定处理模型更新的想法。Aproach有缺陷,导致过多的手动和耦合代码。最好使用模型克隆来初始化两个不同的视图模型。MVVM是一种模式,而不是法律。对于违反模式的一次性挑战,一个简单的解决方案并不是“错误的”。。。模型克隆方法是一种有效的方法,但它可能会在一个简单的场景中增加不必要的复杂性。。。(最初的问题并不意味着一个大型复杂的应用程序)假定它不是一项法律(引用Laurent Buginion的话“MVVM警察不会来”)。但它背后有一个想法,即生成可测试且松散耦合的代码。同样的想法也减少了代码(除了由代码片段处理的样板代码),使项目更易于维护。而且。。。它让你保持理智!1.单向绑定不适合此问题。2.是的,这就是方法,但前提是你有两个不同的视图模型,并且模型就是你所说的对象。3.不是很好的设计,因为它使事情复杂化。分开你的顾虑。。。谢谢你的鱼;-)同意-删除了单向约束注释。我也同意,额外的参数不是一个理想的设计(但它是一种可能性)。我当然会选择对象的副本(在一个单独的视图模型中)-它们是单独的视图(即使“编辑”视图在“列表”视图中同时显示)。这就是我所拥有的。我已经有两个视图模型了。但是,消息传递框架从不创建副本,因此当我在“详细信息”视图中修改该项时,它与列表视图中的对象相同。至于克隆对象,我知道这会起作用,但我希望有更好的方法,因为大多数示例都不会克隆对象。我所说的“更好”是指一种解决方案,我不必在每个类中维护映射列表,我需要为每个类维护映射。@CamronBute:您不必维护映射,两个视图模型(项目视图模型和详细视图模型)都基于同一个模型。消息传递完整模型或仅传递ID,具体取决于您是要从数据库加载数据还是使用客户端上缓存的数据。使用序列化/反序列化机制时,可以非常轻松地创建对象的克隆(例如JavaScriptSerializer)。详图有一个LoadMetro,它将模型克隆并分配给私有属性。这是一份现在可以编辑的副本。