2017-03-05 76 views
0

我正在用UWP,x:Bind和数据验证挣扎了一下。 我有一个非常简单的用例:我希望用户在TextBox中输入int,并在用户离开TextBox后立即在TextBlock中显示该号码。 我可以为TextBox设置InputScope="Number",但这并不妨碍使用键盘输入字符的人(或粘贴某个东西)。 问题是,当我绑定字段与Mode=TwoWay,看来你不能防止System.ArgumentException如果您绑定字段声明为int。如果输入是一个数字,我想检查set方法,但在此之前发生异常。 我的(很简单)视图模型(在这里没有模式,我试图保持尽可能简单):UWP:x:用于数字字段的绑定和数据验证

public class MyViewModel : INotifyPropertyChanged 
{ 
    private int _MyFieldToValidate; 
    public int MyFieldToValidate 
    { 
     get { return _MyFieldToValidate; } 
     set 
     { 
      this.Set(ref this._MyFieldToValidate, value); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void RaisedPropertyChanged([CallerMemberName]string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    protected bool Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null) 
    { 
     if (Equals(storage, value)) 
     { 
      return false; 
     } 
     else 
     { 
      storage = value; 
      this.RaisedPropertyChanged(propertyName); 
      return true; 
     } 
    } 
} 

我后面的代码:

public sealed partial class MainPage : Page 
{ 
    public MyViewModel ViewModel { get; set; } = new MyViewModel() { MyFieldToValidate = 0 }; 

    public MainPage() 
    { 
     this.InitializeComponent(); 
    } 
} 

而且我的整个XAML:

<Page 
    x:Class="SimpleFieldValidation.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:SimpleFieldValidation" 
    xmlns:vm="using:SimpleFieldValidation.ViewModel" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d"> 

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="10*" /> 
      <RowDefinition Height="*" /> 
      <RowDefinition Height="10*" /> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*" /> 
      <ColumnDefinition Width="*" /> 
     </Grid.ColumnDefinitions> 

     <TextBox Grid.Row="1" Grid.Column="0" Text="{x:Bind ViewModel.MyFieldToValidate, Mode=TwoWay}" x:Name="inputText" InputScope="Number" /> 
     <TextBlock Grid.Row="1" Grid.Column="1" Text="{x:Bind ViewModel.MyFieldToValidate, Mode=OneWay}" x:Name="textToDisplay" /> 
    </Grid> 
</Page> 

如果我在TextBox中键入数字字符,则一切正常。但是,如果我输入一个非数值(说“d”)(它甚至没有在set方法的第一支撑为MyFieldToValidate到达断点):

Imgur

是否有一个最佳实践做我想做的事情?最简单的解决方案是防止用户输入其他字符而不是数字,但是我一直在寻找几个小时而没有找到简单的方法......另一个解决方案是在离开字段时验证数据,但是我没有发现与UWP和x:Bind相关的东西(WPF认为很少有东西,但它们不能用UWP复制)。 谢谢!

+0

只是不将其绑定到int,将其绑定到字符串属性,你将通过seters做所有必要的转换和getters(或使用自定义Converter并手动将输入转换为int) – RTDev

回答

4

由于@RTDev表示,您的异常是由系统无法将字符串转换为int引起的。

您可以创建一个类,允许您通过从IValueConverter继承来在源和目标之间转换数据的格式。

您应该始终使用函数式实现实现Convert(Object,TypeName,Object,String),但实现ConvertBack(Object,TypeName,Object,String)非常常见,因此它会报告未实现的异常。如果将转换器用于双向绑定或使用XAML进行序列化,则只需在转换器中使用ConvertBack(Object,TypeName,Object,String)方法。

欲了解更多信息,请参阅IValueConverter Interface

例如:

<Page.Resources> 
    <local:IntFormatter x:Key="IntConverter" /> 
</Page.Resources> 
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="10*" /> 
     <RowDefinition Height="*" /> 
     <RowDefinition Height="10*" /> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*" /> 
     <ColumnDefinition Width="*" /> 
    </Grid.ColumnDefinitions> 
    <TextBox Grid.Row="1" Grid.Column="0" Text="{x:Bind ViewModel.MyFieldToValidate, Mode=TwoWay,Converter={StaticResource IntConverter}}" x:Name="inputText" InputScope="Number" /> 
    <TextBlock Grid.Row="1" Grid.Column="1" Text="{x:Bind ViewModel.MyFieldToValidate, Mode=OneWay}" x:Name="textToDisplay" /> 
</Grid> 

的IntFormatter类:

internal class IntFormatter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, string language) 
    { 
     if (value != null) 
     { 
      return value.ToString(); 
     } 
     else 
     { 
      return null; 
     } 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, string language) 
    { 
     int n; 
     bool isNumeric = int.TryParse(value.ToString(), out n); 
     if (isNumeric) 
     { 
      return n; 
     } 
     else 
     { 
      return 0; 
     } 
    } 
} 
+0

非常感谢您的简单但非常有用的答案。我看着转换器,但没有尝试它们。对于我的验证,我想我会启动另一个线程(稍后)。 – benichka