1

我在 UWPx:Bind和数据验证方面有点挣扎。我有一个非常简单的用例:我希望用户输入int一个TextBoxTextBlock在用户离开后立即在 a 中显示数字TextBox。我可以InputScope="Number"为设置TextBox,但这并不能阻止使用键盘键入的人键入 alpha 字符(或粘贴某些内容)。问题是,当我用 绑定一个字段时,如果您绑定的字段被声明为 ,您Mode=TwoWay似乎无法阻止 a 。如果输入是数字,我想检查该方法,但在此之前发生异常。我的(非常简单的)ViewModel(这里没有模型,我尽量让它尽可能简单):System.ArgumentExceptionintset

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”)(它甚至没有到达setfor 方法第一个括号的断点MyFieldToValidate):

伊姆古尔

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

4

2 回答 2

4

正如@RTDev 所说,您的异常是由系统无法将字符串转换为int 引起的。

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

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

有关详细信息,请参阅IValueConverter 接口

例如:

<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;
        }
    }
}
于 2017-03-06T02:23:59.067 回答
0

如果您不希望用户键入字母数字字符,我认为最优雅的解决方案是创建一个继承自InputBox类的新类NumberBox并重载OnKeyDown方法以拦截字母数字键击,如下所示:

using Windows.System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;

namespace MyProject.Controls
{
    public sealed class NumberBox : TextBox
    {
        protected override void OnKeyDown(KeyRoutedEventArgs e)
        {
            if (e.Key >= VirtualKey.Number0 && e.Key <= VirtualKey.Number9 ||
                e.Key >= VirtualKey.NumberPad0 && e.Key <= VirtualKey.NumberPad9 ||
                e.Key >= VirtualKey.Left && e.Key <= VirtualKey.Down ||
                e.Key == VirtualKey.Delete ||
                e.Key == VirtualKey.Tab ||
                e.Key == VirtualKey.Back ||
                e.Key == VirtualKey.Enter)
                base.OnKeyDown(e);
            else
                e.Handled = true;
        }
    }
}

然后在 XAML 中,添加一个命名空间来引用NumberBox类所在的命名空间,然后将InputBox替换为control:NumberBox,如下所示:

<Page
    x:Class="MyProject.View.CalibrarEnfoque"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:MyProject.View"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:controls="using:MyProject.Controls"
    mc:Ignorable="d">
    <Grid>
        <controls:NumberBox Text="{x:Bind ViewModel.MyValue, Mode=TwoWay}"/>
    </Grid>
</Page>
于 2020-06-17T18:41:49.003 回答