由于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. copy.c实现

    #cat copy.c #include <stdio.h> #include <stdlib.h> #include <string.h> int copyFil ...

  2. Python----DFS---骑士周游问题

    这篇文章将会将一个数据结构与算法中一个很经典很重要的概念——深度优先搜索(Depth-First-Search:DFS).........(你他喵不是在标题里说了吗?) 好吧,DFS的精髓我其实也还没 ...

  3. 洛谷——P2169 正则表达式

    P2169 正则表达式 题目背景 小Z童鞋一日意外的看到小X写了一个正则表达式的高级程序,这个正则表达式程序仅仅由字符“0”,“1”,“.”和“*”构成,但是他能够匹配出所有在OJ上都AC的程序的核心 ...

  4. Java Web项目实战第1篇之环境搭建

    写在前面的话 从今天开始一个Java Web实战项目,参考自 http://blog.csdn.net/eson_15/article/details/51277324 这个博客(非常感谢博主的分享精 ...

  5. ZOJ 5579 Stean

    Stean Time Limit: 1 Second      Memory Limit: 65536 KB      Special Judge Tom is good at making stea ...

  6. noip模拟赛 fateice-or

    分析:or操作只有在结果的这一位为0的情况下才会强制要求两个数的这一位都为0,其它时候不强求,所以为了最大限度地满足条件,我们先把所有的数的所有位全部变成1,如果p的第i位为0,那么[l,r]的数的第 ...

  7. 【学QT】 3 - DEBUG集子

    1. [root@localhost helloqt]# make g++ -Wl,-rpath,/usr/local/qt/lib -o cfconv .obj/main.o .obj/cfconv ...

  8. 使用JQUERY的flexselect插件来实现将SELECT下拉菜单变成自动补全输入框

    这也是下拉列表太长了之后,使用的同事提出来的意见, 然后,本来开始想将DJANGO的那个后台下拉菜单移植过来的,但发现不现实,也麻烦, 就找了几个JQUERY的插件测试了一下,最后选中了flexsel ...

  9. nyoj_91_阶乘之和_201312131321

    阶乘之和 时间限制:3000 ms  |           内存限制:65535 KB 难度:3   描述 给你一个非负数整数n,判断n是不是一些数(这些数不允许重复使用,且为正数)的阶乘之和,如9 ...

  10. LucaCanali --DTRACE AND SYSTEMTAP 脚本工具

    https://github.com/LucaCanali http://cern.ch/canali/