首页 > 解决方案 > 在用户键入类似于来自 wpf 的 PreviewKeyDown 时修改条目的 Text 属性

问题描述

我希望有条件地过滤/更改用户正在键入的Text属性。Entry与 wpf 中的 event相同PreviewKeyDown:在事件之前触发KeyDown,它可以控制在显示给用户之前修改用户的输入,而后者正在输入。

不幸的是,在 Xamarin 中这样的事件并不存在。下面是我迄今为止尝试过的一个示例(将所有内容放在代码隐藏中仅用于示例),但导致堆栈溢出(在Entry_TextChanged事件和notifypropertychanged设置器之间弹跳)。

我的问题不是更正我的代码,而是一种干净的方式来实现上面描述的要求。

PS:对setter进行条件修改不是一种选择,因为它不是一个好的设计,并且不会可重用。


我的页面.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:AppTest"
             x:Class="AppTest.MainPage">

    <StackLayout>
        <Entry Text="{Binding entrystr}"
               Keyboard="Numeric"
               TextChanged="Entry_TextChanged"/>
    </StackLayout>
</ContentPage>

我的页面.xaml.cs

using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;

using Xamarin.Forms;

namespace AppTest
{
    public partial class MainPage : ContentPage, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string _EntryStr;
        public string EntryStr
        {
            get { return _EntryStr; }
            set
            {
                if(Equals(_EntryStr, value))
                {
                    _EntryStr = value;
                    OnPropertyChanged();
                }
            }
        }

        public void OnPropertyChanged([CallerMemberName] string name = null) =>
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

        public MainPage()
        {
            InitializeComponent();
            BindingContext = this;
        }

        private void Entry_TextChanged(object sender, TextChangedEventArgs e)
        {
            float OldValueFloat, NewValueFloat;
            float.TryParse(e.OldTextValue, out OldValueFloat);
            float.TryParse(e.NewTextValue, out NewValueFloat);

            ((sender as Entry).BindingContext as MainPage).EntryStr = NewValueFloat > 5 ?
                OldValueFloat.ToString() : NewValueFloat.ToString();
        }
    }
}

标签: c#xamlxamarineventsxamarin.forms

解决方案


我不太喜欢在 setter 中制作的设计,但似乎没有很多选择,我试图让它更灵活/可重用。


ViewModelBase.cs

public abstract class ViewModelBase: INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void SetProperty<T>(ref T field, T value, Func<T, T, T> PrefilterMethod = null, [CallerMemberName] string name = null)
    {
        if (!Equals(field, value))
        {
            if (PrefilterMethod != null)
                field = PrefilterMethod.Invoke(field, value);
            else
                field = value;
            OnPropertyChanged(name);
        }
    }

    protected void OnPropertyChanged([CallerMemberName] string name = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

MainPageViewModel.cs

public class MainPageViewModel : ViewModelBase
{
    private string _EntryStr;
    public string EntryStr
    {
        get => _EntryStr;
        set => SetProperty(ref _EntryStr, value, Setter_Filter);
    }

private string Setter_Filter(string oldstr, string newstr)
{
    float OldValueFloat, NewValueFloat;
    float.TryParse(oldstr, out OldValueFloat);
    float.TryParse(newstr, out NewValueFloat);

    return  NewValueFloat > 5 ?
            OldValueFloat.ToString() : NewValueFloat.ToString();
}

主页.cs

public MainPage()
{
    InitializeComponent();
    BindingContext = new MainPageViewModel();
}

当然TextChanged,不再需要事件。


推荐阅读