在ShowDialog中将UpdateSourceTrigger设置为Explicit(WPF MVVM)

时间:2011-10-05 07:27:30

标签: wpf data-binding mvvm showdialog updatesourcetrigger

我看到了这个例子 - Binding.UpdateSourceTrigger Property

在示例中,UpdateSourceTrigger设置为Explicit,然后在视图代码中调用TextBox名称的UpdateSource。

但是,如果我使用MVVM dp,我不想让我的控件名称和源属性在VM中而不在视图中,那么将控件绑定到VM属性并将UpdateSourceTrigger设置为显式的正确方法是什么?

我想这样做是因为在我的情况下它的ShowDialog窗口我希望只有当用户点击“确定”时才会更新源

提前致谢!

2 个答案:

答案 0 :(得分:11)

如果您真正使用MVVM,则必须由某些Command处理您的“确定”按钮。此命令必须来自您的ViewModelExpliticly绑定属性必须再次来自ViewModel。所以什么阻止了你。

  1. 请勿使用Explicit绑定,而是使用OneWay绑定。
  2. 在您的按钮中,绑定命令并将命令参数绑定到OneWay绑定的依赖项属性。
  3. 在Command的Execute处理程序(必须是ViewModel中的某个方法)中,使用参数来更改ViewModel的属性。
  4. NotifyPropertyChanged
  5. 中提升该属性的ViewModel

    E.g。

    假设我需要在单击确定按钮上将TextBox的文本更新回我的模型。

    因此,我有一个EmployeeViewModel类,其中包含EmployeeName属性。该物业有一个吸气剂和一个二传手。 setter引发属性更改通知。视图模型还有另一个名为ICommand的{​​{1}}类型的属性,它返回一个命令供我执行。

    SaveNameCommand是我视图的数据上下文类型。 Myview将EmployeeViewModel(名称为x:Name =“EmployeeNameTxBx”)TextBox绑定到OneWay,将按钮绑定为EmployeeName。我将OK属性绑定到Button.Command属性,EmployeeViewModel.SaveNameCommand绑定到Button.CommandParameter属性。

    EmployeeNameTxBx.Text

    在我的 <StackPanel> <TextBox x:Name="EmployeeNameTxBx" Text="{Binding EmployeeName, Mode=OneWay}" /> <Button Content="OK" Command="{Binding SaveNameCommand}" CommandParameter="{Bidning Text, ElementName=EmployeeNameTxBx}" /> </StackPanel> 内,我有EmployeeViewModel方法来执行我的OnSaveNameCommandExecute(object param)

    在此执行此代码......

    SaveNameCommand

    这样只需单击OK按钮,将TextBox的文本更新回模型的 var text = (string)param; this.EmployeeName = text; 属性。

    修改

    查看下面的评论,我发现您正在尝试在UI上实施验证。现在这会改变一些事情。

    仅当您的输入控件(例如TextBoxes) TwoWay 绑定时,

    EmployeeName和相关验证才有效。是的,这就是它的意图。所以现在你可能会问:“这是否意味着如果我们使用IDataErrorInfo,那么不允许将无效数据传递给模型的整个概念在MVVM中是徒劳的”?

    实际上不是!

    请参阅MVVM不会强制执行仅返回有效数据的规则。它接受无效数据,这就是IDataErrorInfo的工作方式,并引发错误通知。关键是ViewModel只是View的软拷贝,因此它可以。它应该确保这种肮脏不会提交到您的外部接口,例如服务或数据库。

    通过测试无效数据,IDataErrorInfo应限制此类无效数据流。如果我们启用了ViewModel绑定,那么这些数据就会出现。因此,考虑到您正在实现TwoWay,那么您需要拥有IDataErrorInfo绑定,这在MVVM中是完全允许的。

    方法1:

    如果我想在按钮点击时明确验证用户界面上的某些项目该怎么办?

    对于此用途,延迟验证技巧。在您的ViewModel中有一个名为isValidating的标志。默认设置为false。

    TwoWay属性中,通过检查isValidating标志...

    跳过验证
    IDataErrorInfo.this

    然后在您的OK命令执行处理程序中,检查员工姓名,然后为同一属性提出属性更改通知事件...

        string IDataErrorInfo.this[string columnName]
        {
          get
          {
            if (!isValidating) return string.Empty;
    
            string result = string.Empty;
            bool value = false;
    
            if (columnName == "EmployeeName")
            {
                if (string.IsNullOrEmpty(AccountType))
                {
                    result = "EmployeeName cannot be empty!";
                    value = true;
                }
            }
            return result;
          }
        }
    

    仅在单击“确定”时触发验证。请记住, private void OnSaveNameCommandExecute(object param) { isValidating = true; this.NotifyPropertyChanged("EmployeeName"); isValidating = false; } 必须包含无效数据才能使验证生效。

    方法2:

    如果我想在MVVM中显式更新没有TwoWay模式的绑定怎么办?

    然后你必须使用EmployeeName。该行为将附加到“确定”按钮,并将接受需要刷新其绑定的所有项目的列表。

    Attached Behavior

    <Button Content="OK"> <local:SpecialBindingBehavior.DependentControls> <MultiBinding Converter="{StaticResource ListMaker}"> <Binding ElementName="EmployeeNameTxBx" /> <Binding ElementName="EmployeeSalaryTxBx" /> .... <MultiBinding> </local:SpecialBindingBehavior.DependentControls> </Button> ListMaker,它只是将值转换为列表...

    IMultiValueConverter

    在您的 Convert(object[] values, ...) { return values.ToList(); } 中有SpecialBindingBehavior属性更改处理程序...

    DependentControls

    但我仍然建议你使用我以前的纯MVVM **方法1

答案 1 :(得分:1)

这是一个古老的问题,但我仍然想为偶然发现这个问题的其他用户提供另一种方法...... 在我的viewmodels中,我没有直接在get / set Property方法中公开模型属性。我为所有属性使用内部变量。然后我双向绑定所有属性。所以我可以做所有的验证,因为&#34;通常&#34;因为只有内部变量被改变了。在视图模型构造函数中,我将模型对象作为参数,并将内部变量设置为我的模型的值。现在当我点击&#34; Save&#34;按钮( - &gt;保存命令在我的视图模型中触发)并且没有错误,我将模型的所有属性设置为相应内部变量的值。如果我点击&#34; Canel / Undo&#34; -Button(在我的视图模型中触发&gt;取消 - 命令),我将内部变量设置为我未触摸模型的值(使用视图的设置者)模型属性,以便调用NotifyPropertyChanged并且视图显示更改=旧值。)

另一种方法是在模型中实现Memento-Support,因此在开始编辑之前,调用模型中的函数来保存当前值,如果取消编辑,则调用函数来恢复这些值。那么你不仅可以在一个视图模型中获得撤消/取消支持... 我在不同的项目中实现了这两种方法,并且都运行良好,这取决于项目的要求......