单击按钮后激活 CharactersValidationBehavior

问题描述 投票:0回答:2

单击按钮后,如何激活或重新评估为条目设置的 CharactersValidationBehavior 的结果?

<Entry.Behaviors>

    <toolkit:CharactersValidationBehavior IsValid="{Binding InputValid}"
                                          Flags="ValidateOnValueChanged"                                                         
                                          CharacterType="Alphanumeric"
                                          MinimumCharacterTypeCount="1" />
                                                
</Entry.Behaviors>

非可选条目在 XAML 中正确设置,并在 ContentView 显示后立即在 ContentView 的代码隐藏中的 InputValid-Property 中进行评估。但我真正想要的是,在单击按钮后立即进行评估。

我怎么能这样做?

xaml maui code-behind
2个回答
0
投票

可以添加按钮事件进行点击后验证,然后定义Entry控件的焦点事件。当Entry获得焦点时,去掉验证,这样就可以达到点击激活或者重新评价的目的。我写了一个demo来测试一下。可以参考下面的代码

Xaml文件:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="MauiApp7.MainPage">
    <ContentPage.Resources>
        <Style x:Key="InvalidEntryStyle" TargetType="Entry" x:Name="invalidStyle">
            <Setter Property="TextColor" Value="Red" />
        </Style>
        <Style x:Key="ValidEntryStyle" TargetType="Entry" x:Name="validStyle">
            <Setter Property="TextColor" Value="Green" />
        </Style>
    </ContentPage.Resources>

    <StackLayout>
        <Entry x:Name="enrty" Focused="OnEntryFocused" >
            <Entry.Behaviors>
                <toolkit:CharactersValidationBehavior x:Name="charactersValidationBehavior"/>
            </Entry.Behaviors>
        </Entry>

        <Button Text="Evaluate" Clicked="OnEvaluated"/>

</ContentPage>

.CS文件:

using CommunityToolkit.Maui.Behaviors;

namespace MauiApp7;

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    private void OnEvaluated(object sender, EventArgs e) {
        charactersValidationBehavior.InvalidStyle = invalidStyle;
        charactersValidationBehavior.ValidStyle = validStyle;
        charactersValidationBehavior.Flags = ValidationFlags.ValidateOnValueChanged;
        charactersValidationBehavior.CharacterType = CharacterType.Digit;
        charactersValidationBehavior.MinimumCharacterTypeCount = 3;  
        enrty.Behaviors.Add(charactersValidationBehavior);
    }

    private void OnEntryFocused(object sender, EventArgs e) {
        enrty.Behaviors.Remove(charactersValidationBehavior);
    }
}

0
投票

我试图实现你的基本概念,但它似乎没有像我想要的那样工作。

基本上,我想稍微修改一下,当用户在相应条目中输入的内容未正确验证时,我想显示一个图标或一个带有文本的标签。

在我的例子中,我有一个 ContentPage 使用几个 ContentViews 来承载条目和标签,还有应该以红色或类似的东西显示错误消息的标签。

内容页:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:viewModels="clr-namespace:MyApp.ViewModels"
             xmlns:controls="clr-namespace:MyApp.Pages.Views"
             x:DataType="viewModels:ManageItemsViewModel"
             x:Class="MyApp.Pages.ManageItems"
             Title="Some title">

    <VerticalStackLayout>

        <Label 
            Text="Addn Items"
            FontAttributes="Bold"
            VerticalOptions="Center" 
            HorizontalOptions="Center"
            Padding="20" />

        <StackLayout>
            <controls:MyItemInputControlView NameLabelString="Label for Input 1:"
                                             IsOptionalLabelString="Mandatory"
                                             PlaceholderString="a placeholder 1"
                                             EntryInput="{Binding Item.Name}"
                                             InputValid="{Binding NameInput1Valid, Mode=TwoWay}" />

            <controls:MyItemInputControlView NameLabelString="Label for Input 2:"
                                             IsOptionalLabelString="Optional"
                                             PlaceholderString="a placeholder 2"
                                             EntryInput="{Binding Item.Brand}"
                                             InputValid="{Binding NameInput2Valid, Mode=TwoWay}" />
            

            <StackLayout Margin="20, 50, 15, 0">
                <Grid RowSpacing="10">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>

                    <Button Grid.Row="0" Grid.Column="0" Margin="5"
                            Text="OK"
                            Command="{Binding SaveItemCommand}" />

                    <Button Grid.Row="0" Grid.Column="1" Margin="5"
                            Text="Cancel"
                            Command="{Binding CancelItemCommand}" />
                </Grid>
            </StackLayout>
        </StackLayout>

    </VerticalStackLayout>

</ContentPage>

内容视图:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             xmlns:views="clr-namespace:MyApp.Pages.Views"
             x:Class="MyApp.Pages.Views.MyItemInputControlView"
             x:Name="this">


    <ContentView.Resources>
        <ResourceDictionary>
            <toolkit:InvertedBoolConverter x:Key="InvertBoolValueConverter" />
        </ResourceDictionary>
    </ContentView.Resources>

    <StackLayout BindingContext="{x:Reference this}">
        <Grid Margin="20, 0, 20, 0">
            <Grid.Resources>
                <!--<Style TargetType="Entry">
                    <Setter Property="Padding" Value="2 1" />
                    <Setter Property="BorderBrush" Value="LightGray" />
                </Style>-->
            </Grid.Resources>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>


            <StackLayout Grid.Row="0" Grid.Column="0" VerticalOptions="Center">
                <Label Text="{Binding NameLabelString}" />
                <Label Text="{Binding IsOptionalLabelString}"  FontSize="12" />
            </StackLayout>

            <StackLayout Grid.Row="0" Grid.Column="1" VerticalOptions="Center" >
                <Entry Text="{Binding EntryInput}" Placeholder="{Binding PlaceholderString}" Keyboard="{Binding KeyboardSetting}" Margin="5, 0, 5, 15" x:Name="entryControl">
                    <Entry.Behaviors>

                        <!--<toolkit:CharactersValidationBehavior IsValid="{Binding InputValid}"
                                                              Flags="ValidateOnUnfocusing,ValidateOnValueChanged"                                                         
                                                              CharacterType="Alphanumeric"
                                                              MinimumCharacterTypeCount="1" />-->

                    </Entry.Behaviors>
                </Entry>
                <Label Text="{Binding NameLabelString}" TextColor="Red" IsVisible="{Binding InputValid, Converter={StaticResource InvertBoolValueConverter}}"/>
            </StackLayout>

            <StackLayout Grid.Row="0" Grid.Column="2" VerticalOptions="Center" >
                <Label Text="{Binding MeasurementUnitString}"/>
            </StackLayout>
        </Grid>
    </StackLayout>

</ContentView>

ContentView 代码隐藏:

namespace MyApp.Pages.Views;

public partial class MyItemInputControlView : ContentView
{
    public static readonly BindableProperty NameLabelProperty = BindableProperty.Create(nameof(NameLabelString), typeof(string), typeof(FoodItemInputControlView), string.Empty, BindingMode.OneWay);
    public static readonly BindableProperty IsOptionalProperty = BindableProperty.Create(nameof(IsOptionalLabelString), typeof(string), typeof(FoodItemInputControlView), string.Empty);
    public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create(nameof(PlaceholderString), typeof(string), typeof(FoodItemInputControlView), string.Empty);
    public static readonly BindableProperty MeasurementUnitProperty = BindableProperty.Create(nameof(MeasurementUnitString), typeof(string), typeof(FoodItemInputControlView), string.Empty);
    public static readonly BindableProperty KeyboardSettingProperty = BindableProperty.Create(nameof(KeyboardSetting), typeof(Keyboard), typeof(FoodItemInputControlView), Keyboard.Default);
    public static readonly BindableProperty EntryInputProperty = BindableProperty.Create(nameof(EntryInput), typeof(string), typeof(FoodItemInputControlView), string.Empty, BindingMode.TwoWay);

    public static readonly BindableProperty InputValidProperty = BindableProperty.Create(nameof(InputValid), typeof(bool), typeof(FoodItemInputControlView), true, BindingMode.OneWayToSource);


    public string NameLabelString
    {
        get => (string)GetValue(NameLabelProperty);
        set => SetValue(NameLabelProperty, value);
    }

    public string IsOptionalLabelString
    {
        get => (string)GetValue(IsOptionalProperty);
        set => SetValue(IsOptionalProperty, value);
    }

    public string PlaceholderString
    {
        get => (string)GetValue(PlaceholderProperty);
        set => SetValue(PlaceholderProperty, value);
    }

    public string MeasurementUnitString
    {
        get => (string)GetValue(MeasurementUnitProperty);
        set => SetValue(MeasurementUnitProperty, value);
    }

    public Keyboard KeyboardSetting
    {
        get => (Keyboard)GetValue(KeyboardSettingProperty);
        set => SetValue(KeyboardSettingProperty, value);
    }

    public string EntryInput
    {
        get => (string)GetValue(EntryInputProperty);
        set => SetValue(EntryInputProperty, value);
    }

    


    public bool InputValid
    {
        get => (bool)GetValue(InputValidProperty);
        set
        {
            // Before everything is initialized TextValidation should be valid
            if ((string.IsNullOrEmpty(IsOptionalLabelString) || IsOptionalLabelString.Equals("Optional")))
            {
                value = true;
            }

            SetValue(InputValidProperty, value);
        }
    }


    public MyItemInputControlView()
    {
        InitializeComponent();

        this.Loaded += MyItemInputControlView_Loaded;
        WeakReferenceMessenger.Default.Register<SaveButtonClickedMessage>(this, HandleSaveButtonClickedMessage);
    }

    private void HandleSaveButtonClickedMessage(object recipient, SaveButtonClickedMessage message)
    {
        var binding = new Binding("IsValid", BindingMode.TwoWay);
        charactersValidationBehavior.SetBinding(InputValidProperty, binding);

        charactersValidationBehavior.Flags = ValidationFlags.ValidateOnValueChanged | ValidationFlags.ValidateOnAttaching;
        charactersValidationBehavior.CharacterType = CharacterType.Alphanumeric;
        charactersValidationBehavior.MinimumCharacterTypeCount = 1;

        entryControl.Behaviors.Add(charactersValidationBehavior);
    }

    private void MyItemInputControlView_Loaded(object sender, EventArgs e)
    {
        entryControl.Behaviors.Remove(charactersValidationBehavior);
    }
}

ContentPage 的 ViewModel:

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using MacroCalculatorApp.Models;
using SQLite;
using System.ComponentModel;

namespace MyApp.ViewModels
{
    public partial class ManageItemViewModel : ObservableObject, INotifyPropertyChanged
    {
        [ObservableProperty]
        private MyItem myItem;


        
        private bool InputsValid => true; // needs further evaluation if everything on the ContentView is correct



        [RelayCommand]
        async Task SaveItem()
        {
            WeakReferenceMessenger.Default.Send(new SaveButtonClickedMessage(true));

            try
            {
                if (InputsValid)
                {
                    ...

                    // Just navigate to the previous page
                    await Shell.Current.GoToAsync("..");
                }
            }
            catch (SQLiteException sqliteException)
            {
                ...
            }
            catch (Exception e)
            {
                await App.Current.MainPage.DisplayAlert("Error", e.Message, "OK");
            }
        }

        [RelayCommand]
        async Task CancelItem()
        {
            // Just navigate to the previous page
            await Shell.Current.GoToAsync("..");
        }

        public ManageMyItemViewModel()
        {
            MyItem = new MyItem();
        }
    }
}

我向 ContentView 的代码隐藏发送一个简单的消息(仅包含值 true)以检测按钮单击。

不幸的是,当我分配 CharactersValidationBehavior 时,它不会评估 ContentViews 的条目。此外,绑定“InputValid”-Property 的值在调试时可以为 false,然后当显示 ContentView 时标签可见并显示红色错误消息。我可以用标签本身的“Mode=TwoWay”选项来抑制这一点。

任何想法,我在这里做错了什么?

© www.soinside.com 2019 - 2024. All rights reserved.