由于Binding只把Convert成功的值送往Source,当目标中的值Convert失败时Source的值依然是旧值,所以ViewModel必须获取View的输入验证状态,以下是本人的实现。

当“+”号两边输入正确时,“Add”可用,当所有“+”号两边输入正确时,“Add All”可用。

通过Behavior添加Validation.ErrorEvent路由事件的事件处理器,在该事件处理器中把HasError状态写入自定义的附加属性,附加属性可以绑定。

Behavior派生类引用System.Windows.Interactivity.dll,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity; namespace Calculater
{
public class NotifyErrorBehavior : Behavior<UIElement>
{
protected override void OnAttached()
{
base.OnAttached(); this.AssociatedObject.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(HasErrorChanged));
} protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.RemoveHandler(Validation.ErrorEvent, new RoutedEventHandler(HasErrorChanged));
} private static void HasErrorChanged(object sender, RoutedEventArgs e)
{
DependencyObject d = e.OriginalSource as DependencyObject;
HasErrorHelper.SetHasError(d, Validation.GetHasError(d));
}
}
}

附加属性代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls; namespace Calculater
{
public class HasErrorHelper
{
public static bool GetHasError(DependencyObject obj)
{
return (bool)obj.GetValue(HasErrorProperty);
} public static void SetHasError(DependencyObject obj, bool value)
{
obj.SetValue(HasErrorProperty, value);
} public static readonly DependencyProperty HasErrorProperty =
DependencyProperty.RegisterAttached("HasError", typeof(bool), typeof(HasErrorHelper), new PropertyMetadata(false));
}
}

View代码:

<UserControl x:Class="Calculater.ChildCalculater"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Calculater"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
d:DesignHeight="" d:DesignWidth="">
<i:Interaction.Behaviors>
<local:NotifyErrorBehavior></local:NotifyErrorBehavior>
</i:Interaction.Behaviors>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Margin="" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" local:HasErrorHelper.HasError="{Binding Path=HasErrorX,Mode=OneWayToSource}">
<Binding Path="X" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged" TargetNullValue="" />
</TextBox>
<Label Margin="" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Grid.Column="">+</Label>
<TextBox Margin="" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.Column="" local:HasErrorHelper.HasError="{Binding Path=HasErrorY,Mode=OneWayToSource}">
<Binding Path="Y" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged" TargetNullValue="" />
</TextBox>
<Label Margin="" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Grid.Column="">=</Label>
<TextBox Margin="" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.Column="" IsReadOnly="True">
<Binding Path="Sum" TargetNullValue="" />
</TextBox>
<Button Margin="" Grid.Column="" Padding="" Command="{Binding CalculateCommand}">Add</Button>
<Button Margin="" Grid.Column="" Padding="" Command="{Binding ResetCommand}">Reset</Button>
</Grid>
</UserControl>

ViewModel引用Microsoft.Practices.Prism.dll,代码如下:

using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace Calculater
{
class ChildCalculaterViewModel : NotificationObject
{
public ChildCalculaterViewModel()
{
this._calculateCommand = new DelegateCommand(this.Calculate, this.CanCalculate);
this._resetCommand = new DelegateCommand(this.Reset); CalculaterCommand.CalculateAllCommand.RegisterCommand(this.CalculateCommand);
CalculaterCommand.ResetAllCommand.RegisterCommand(this.ResetCommand); } private double? _x; public double? X
{
get { return _x; }
set
{
if (_x != value)
{
_x = value;
this.RaisePropertyChanged("X");
this.Sum = null;
this.CalculateCommand.RaiseCanExecuteChanged();
} }
} private double? _y; public double? Y
{
get { return _y; }
set
{
if (_y != value)
{
_y = value;
this.RaisePropertyChanged("Y");
this.Sum = null;
this.CalculateCommand.RaiseCanExecuteChanged();
} }
} private double? _sum; public double? Sum
{
get { return _sum; }
set
{
if (_sum != value)
{
_sum = value;
this.RaisePropertyChanged("Sum");
} }
} private bool _hasErrorX; public bool HasErrorX
{
get { return _hasErrorX; }
set
{
if (_hasErrorX != value)
{
_hasErrorX = value;
this.Sum = null;
this.CalculateCommand.RaiseCanExecuteChanged();
} }
} private bool _hasErrorY; public bool HasErrorY
{
get { return _hasErrorY; }
set
{
if (_hasErrorY != value)
{
_hasErrorY = value;
this.Sum = null;
this.CalculateCommand.RaiseCanExecuteChanged();
} }
} private DelegateCommand _calculateCommand; public DelegateCommand CalculateCommand
{
get { return _calculateCommand; }
} private bool CanCalculate()
{
if (this.HasErrorX || this.HasErrorY || !this.X.HasValue || !this.Y.HasValue)
{
return false;
} return true;
} private void Calculate()
{
try
{
double x = this.X.Value;
double y = this.Y.Value; this.Sum = x + y;
}
catch
{
return;
}
} private DelegateCommand _resetCommand; public DelegateCommand ResetCommand
{
get { return _resetCommand; }
} private void Reset()
{
this.X = null;
this.Y = null;
this.Sum = null;
}
}
}

主窗体代码:

<Window x:Class="Calculater.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Calculater"
xmlns:prism="http://www.codeplex.com/prism"
Title="Calculater" Height="" Width="">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<local:ChildCalculater></local:ChildCalculater>
<local:ChildCalculater Grid.Row=""></local:ChildCalculater>
<local:ChildCalculater Grid.Row=""></local:ChildCalculater>
<Grid Grid.Row="">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Margin="" HorizontalAlignment="Right" Padding="" Content="Add All" Command="{x:Static local:CalculaterCommand.CalculateAllCommand}"></Button>
<Button Margin="" HorizontalAlignment="Left" Padding="" Grid.Column="" Content="Reset All" Command="{x:Static local:CalculaterCommand.ResetAllCommand}"></Button>
</Grid>
</Grid>
</Window>
using Microsoft.Practices.Prism.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Calculater
{
public static class CalculaterCommand
{
private static CompositeCommand _calculateAllCommand = new CompositeCommand(); public static CompositeCommand CalculateAllCommand
{
get { return _calculateAllCommand; }
} private static CompositeCommand _resetAllCommand = new CompositeCommand(); public static CompositeCommand ResetAllCommand
{
get { return _resetAllCommand; }
} }
}

MVVM实现ViewModel获取View输入验证状态的更多相关文章

  1. [WPF] 在 ViewModel 中让数据验证出错(Validation.HasError)的控件获得焦点

    1. 需求 在 MVVM 中 ViewModel 和 View 之间的交互通常都是靠 Icommand 和 INotifyPropertyChanged,不过有时候还会需要从 MVVM 中控制 Vie ...

  2. MVVM模式下,ViewModel和View,Model有什么区别

    摘自正美的5群 Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model. View:也很简单,就是展现出来的用户界面. 基本上,绝大多数软件所做的工 ...

  3. js架构设计模式——MVVM模式下,ViewModel和View,Model有什么区别

    MVVM模式下,ViewModel和View,Model有什么区别 Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model. View:也很简单,就 ...

  4. MVVM模式中ViewModel和View、Model有什么区别

    Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model. View:也很简单,就是展现出来的用户界面. 基本上,绝大多数软件所做的工作无非就是从数据 ...

  5. WPF MVVM(Caliburn.Micro) 数据验证

    书接前文 前文中仅是WPF验证中的一种,我们暂且称之为View端的验证(因为其验证规是写在Xaml文件中的). 还有一种我们称之为Model端验证,Model通过继承IDataErrorInfo接口来 ...

  6. 获取view宽高

    在oncreate()中利用view.getWidth()或是view.getHeiht()来获取view的宽和高,看似没有问题,其实他们去得值是0,并不是你想要的结果? 这是为什么呢? 在调用onc ...

  7. [Swift通天遁地]二、表格表单-(8)快速实现表单的输入验证

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  8. silverlight wpf Command提交时输入验证

    silverlight 或WPF在MVVM模式中使用INotifyDataErrorInfo接口对输入进行验证时 控件lostFocus时会触发验证,但在提交动作(例如button的Command)时 ...

  9. Struts2的输入验证

    一.概述: ① Struts2的输入验证 –基于 XWorkValidation Framework的声明式验证:Struts2提供了一些基于 XWork Validation Framework的内 ...

随机推荐

  1. Ubuntu 16.04 安装R和RStudio

    在Ubuntu上安装R和Rstudio的时候碰到了一些依赖项不存在的错误 The following packages have unmet dependencies: r-base-core : D ...

  2. TypeError与ValueError的区别

    typeerror:函数或方法接受了不适当的[类型]的参数,比如sum('nick'),sum函数不接受字符串类型:valueerror:函数或方法虽然接受了正确的[类型]的参数,但是该参数的[值]不 ...

  3. Python类中的 私有变量和私有方法

    默认情况下,Python中的成员函数和成员变量都是公开的(public),在python中没有类似public,private等关键词来修饰成员函数和成员变量.在python中定义私有变量只需要在变量 ...

  4. 解决WP程序 重复打开出现 “正在加载...” 字样 解决方案

    在开发winphone程序时候 我们经常遇到调试.在调试的时候 可能会重复打开 debug一下.可是有时候 经常遇到 "正在加载...."字样.而且很慢.效率很低. 测试发现 在 ...

  5. hive计算日期差

    首先,hive本身有一个UDF,名字是datediff.我们来看一下这个日期差计算的官方描述,(下面这个是怎么出来的): hive> desc function extended datedif ...

  6. springMVC入门笔记

    目录 一.回顾Servlet 二.SpringMVC简介 三.搭建SpringMVC第一个案例 四.简单流程及配置 五.使用注解开发Controller 六.参数绑定 基本数据类型的获取: 如果表单域 ...

  7. insert into varchar2(8000)

    在看12c的文档的时候发现varcahr2最大长度是4000 byte VARCHAR2 Data Type The VARCHAR2 data type specifies a variable-l ...

  8. 机器学习4logistic回归

    对于线性回归.logistic回归,在以前准备学习深度学习的时候看过一点,当时的数学基础有点薄弱,虽然现在还是有点差,当时看到神经网络之后就看不下去了. 不过这次是通过python对logistic回 ...

  9. 最新版本号cocos2d&#173;2.0&#173;x&#173;2.0.2使用新资源载入策略!不再沿用-hd、-

     前段时间cocos2dx更新了最新版本号cocos2d­2.0­x­2.0.2.也从这个版本号開始对于资源载入与管理都改变了策略. 在之前的载入方式都是通过沿用与cocos2d-iphone一样 ...

  10. Atitit. C# java 的api 文件夹封装结构映射总结

    Atitit. C#  java 的api 文件夹封装结构映射总结 C# java ref System.Reflection System.Type. java.lang.ref concurren ...