由于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. 安装部署NetBeans mysql Tomact joget workflow 环境

    一.安装joget workflow 1.安装jdk 下载jdk http://www.oracle.com/technetwork/java/javase/downloads/index.html ...

  2. 洛谷——P1122 最大子树和

    P1122 最大子树和 树形DP,$f[u]$表示以u为根的子树的最大美丽指数 $f[u]+=max(0,f[v])$ 树形DP的基本结构,先搜再DP,这题感觉有点儿贪心的性质,选就要选美丽值> ...

  3. hstack()与vstack()函数

    ref: https://blog.csdn.net/csdn15698845876/article/details/73380803 1. hstack()函数 a,b只有一个维度:对第一个维度拼接 ...

  4. 【模板】Hash

    洛谷3370 这题煞笔的吧QAQ......排序去重或者Map都可以 #include<cstdio> #include<map> #include<string> ...

  5. 【Codeforces 1114C】Trailing Loves (or L'oeufs?)

    [链接] 我是链接,点我呀:) [题意] 问你n!的b进制下末尾的0的个数 [题解] 证明:https://blog.csdn.net/qq_40679299/article/details/8116 ...

  6. Master Nginx(8) - Troubleshooting Techniques

    Analyzing log files Error log file formats Error log file entry examples Configuring advanced loggin ...

  7. paste deploy初探

    这段时间刚着手开始研究Openstack Swift源码,为后续开发做准备. Swift依据python WSGI规范.WSGI(Web Server Gateway Interface)是Pytho ...

  8. PatentTips - Indexes of graphics processing objects in GPU commands

    BACKGROUND A graphics processing unit (GPU) is a specialized electronic device that is specifically ...

  9. hdu_1061_Rightmost Digit_201311071851

    Rightmost Digit Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  10. asp.net--mvc--异步编程

    Using Asynchronous Methods in ASP.NET MVC 4 asp.net mvc中的异步只能增加系统的性能,原来需要500个线程的,现在需要50个就够了,对一些常规的程序 ...