WPF中MVVM子窗口修改数据问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF中MVVM子窗口修改数据问题相关的知识,希望对你有一定的参考价值。

WPF中用MVVM模式,有两个窗口,父窗口是数据列表,子窗口为修改窗口,子窗口的文本框数据变化了父窗口也跟这变化了,这是怎么回事啊?还没点击确定按钮

这么说吧,wpf里的数据绑定就是给数据源(source)和显示数据的绑定对象(target)建立一个关系。绑定模式呢一般有单向绑定和双向绑定的(默认为单向绑定,且当数据源实现INotifyPropertyChanged接口时,数据源改变可以导致前台显示改变)如果是双向绑定呢,source和target只要有一方改变,另外一方也会随之改变。楼主的例子中两个窗口都是target,而父窗口列表里selectedItem和子窗口的文本框绑定的应该是viewModel里同一个对象。当子窗口target发生更改,它会通知到viewModel这个source,然后这个source呢,就会通知到主窗口这个target。啊,对了,一般情况下呢,触发数据变化是“失去焦点”,就是你所谓的点击确定按钮让子窗口文本框失去焦点的情况下。但如果在绑定的时候有设置UpdateSourceTrigger=PropertyChanged,那就会实现实时更改数据了。追问

设置为了UpdateSourceTrigger=PropertyChanged,ViewModel层就接收不到改变后的数据了,这是怎么回事呢?我所要达到的目的是要点击确定后再更新数据源的数据啊。

追答

首先设置为了UpdateSourceTrigger=PropertyChanged,ViewModel层不会不收到改变后的数据,因为前台任何一点的改变都会通知到viewmodel层。其次,你的的目的是要点击确定后再更新数据源的数据。所以用默认的形式就可以了,不需要设置UpdateSourceTrigger=PropertyChanged。默认情况为失去焦点再更新数据。

追问

失去焦点就更新数据也是不行的,我还没点击确定按钮,在填写下一个文本框的数据时,第一个文本框的数据源就已经更新了。就是说我还没点击确定按钮,只是文本框失去焦点就更新了,这样是不行的。必须点击确定按钮后更新。明白意思没啊。麻烦大侠解答啊。

追答

明白了,这也不是很简单么。UpdateSourceTrigger不是有三种方式么,请选择Explicit
给你篇文章参考http://www.silverlightchina.net/html/tips/2010/0920/1946.html

参考技术A 这就是绑定的强大之处。或者说它们本来用的就是同一个数据源。要想点确定再触发,则要改变子窗口的数据绑定对象。追问

改变子窗口的数据绑定对象??不会吧,这么麻烦啊,有没有方便点的方法呢?

追答

没有。

追问

我相信是有的。

WPF MVVM 将用户控件绑定到主窗口视图模型

【中文标题】WPF MVVM 将用户控件绑定到主窗口视图模型【英文标题】:WPF MVVM Bind User Control to Main Window View Model 【发布时间】:2013-07-22 05:46:56 【问题描述】:

我不久前在这里WPF MVVM User Control 提出了类似的问题。我得到了一些答案,但它们离我很远,所以我想我并不清楚我想做什么......

我正在使用 MVVM 开发 WPF 应用程序。该应用程序是使用基于组件的方法构建的,因此我定义了一些将在整个应用程序中使用的用户控件。例如,我有一个地址控件。我想在整个应用程序的多个地方使用它。这是一个例子。见这里:

http://sdrv.ms/1aD775H

带有绿色边框的部分是地址控件。该控件有自己的视图模型。

当我将它放在窗口或其他控件上时,我需要告诉它要为其加载地址的客户的 PK。所以我创建了一个客户 ID DependencyProperty:

public partial class AddressView : UserControl

    public AddressView()
    
        InitializeComponent();
    

    public static DependencyProperty CustomerIdProperty = DependencyProperty.Register("CustomerId", typeof(int), typeof(AddressView),
        new UIPropertyMetadata(0, AddressView.CustomerIdPropertyChangedCallback, AddressView.CustomerIdCoerce, true));


    public int CustomerId
    
        // THESE NEVER FIRE
        get  return (int)GetValue(CustomerIdProperty); 
        set  SetValue(CustomerIdProperty, value); 
    

    private static void CustomerIdPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs args)
    
        // THIS NEVER FIRES
        AddressView instance = (AddressView)d;
        instance.CustomerId = (int)args.NewValue;
    
    enter code here
    private static object CustomerIdCoerce(DependencyObject d, object value)
    
        return value;   // <=== THIS FIRES ON STARTUP
    

然后在 MainWindowView 我有:

<vw:AddressView Grid.Row="1"
                Grid.Column="0"
                x:Name="AddressList"
                CustomerId="Binding ElementName=TheMainWindow, Path=SelectedCustomer.Id, Mode=TwoWay"/>

注意我在用户控件的 CS 中的 cmets。 Coerce 在启动时触发。回调永远不会触发,CustomerId getter 或 setter 也不会触发。

我想要发生的事情看起来很简单,我就是做不到......

选择客户时,应将 CustomerId 传递给 Address UserControl。然后在 VM 中的地址 UserControl 应该处理获取和保存数据。

所以,再次提出两个问题:

1) 有人知道出了什么问题吗?

2) UserControl DP如何将PK发送到ViewModel?

如果有人感兴趣,我的示例项目在这里:http://sdrv.ms/136bj91

谢谢

【问题讨论】:

try adding UpdateSourceTrigger=PropertyChanged to your binding, when the selection changes your control won't get updated otherwise. 你能发布你的usercontrol xaml页面的代码吗.. WPF MVVM User Control 的可能副本 【参考方案1】:

在这种情况下,您的 CustomerId getter 和 setter 永远不会触发。它们只是作为辅助方法存在,以防想要从您的代码后面访问CustomerIdProperty 属性。

您的CustomerIdPropertyChangedCallback 方法不会触发,因为您的绑定表达式不正确。您需要绑定到 DataContextMainWindow 而不是窗口本身:

...
CustomerId="Binding ElementName=TheMainWindow, Path=DataContext.SelectedCustomer.Id"
...

此外,请确保在绑定到 ComboBox 的属性发生更改时调用 INotifyPropertyChanged PropertyChanged 事件。

【讨论】:

【参考方案2】:

试试这个:

CustomerId="Binding RelativeSource=RelativeSource FindAncestor, 
AncestorType=x:Type Window, Path=DataContext.YourSelectedItem.TheProperty"

我不知道如何管理您在窗口中选择的项目,所以请相应地更改yourSelectedItem.TheProperty

【讨论】:

好的,这有效 - 但只有一次。回调方法仅在第一次选择客户时触发。 你能在代码中粘贴你的 SelectedItem 的实现吗 当然,我创建了一个小型沙盒项目来学习这一点。在这里sdrv.ms/13fM5EY。

以上是关于WPF中MVVM子窗口修改数据问题的主要内容,如果未能解决你的问题,请参考以下文章

WPF FileFolderDialog 和弹出子窗口的一些问题

如何在WPF中单击菜单项时在父窗口下打开子窗口?

如何在WPF中进行模态对话?

WPF子页面获取父框架

WPF 子窗体 在 父窗体 中 打开,初学不懂,请指教

在 WPF 窗口中禁用除一个子控件之外的所有子控件