单击按钮后,如何激活或重新评估为条目设置的 CharactersValidationBehavior 的结果?
<Entry.Behaviors>
<toolkit:CharactersValidationBehavior IsValid="{Binding InputValid}"
Flags="ValidateOnValueChanged"
CharacterType="Alphanumeric"
MinimumCharacterTypeCount="1" />
</Entry.Behaviors>
非可选条目在 XAML 中正确设置,并在 ContentView 显示后立即在 ContentView 的代码隐藏中的 InputValid-Property 中进行评估。但我真正想要的是,在单击按钮后立即进行评估。
我怎么能这样做?
可以添加按钮事件进行点击后验证,然后定义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);
}
}
我试图实现你的基本概念,但它似乎没有像我想要的那样工作。
基本上,我想稍微修改一下,当用户在相应条目中输入的内容未正确验证时,我想显示一个图标或一个带有文本的标签。
在我的例子中,我有一个 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”选项来抑制这一点。
任何想法,我在这里做错了什么?