You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI中ViewModel引用x:Name定义的TextValidationBehavior报错解决

在.NET MAUI中访问ContentView内TextValidationBehavior的IsValid属性

问题场景

我在.NET MAUI项目中创建了MyFoodInputControlView这个ContentView,其中Entry控件包含一个x:Name为myTextValidationBehavior的TextValidationBehavior。该ContentView被用于ManageItem页面,页面绑定的ManageItemsViewModel中,SaveItem命令需要访问这个TextValidationBehavior的IsValid属性,但直接引用时提示“名称'myTextValidationBehavior'在当前上下文中不存在”,请问如何正确获取该验证状态?

相关代码

ContentView代码(MyFoodInputControlView.xaml)

<?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"
             x:Class="MyApp.Pages.Views.MyFoodInputControlView"
             x:Name="this">

    <StackLayout BindingContext="{x:Reference this}">
        <Grid Margin="20, 0, 20, 0">
            <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">
                    <Entry.Behaviors>
                        <toolkit:TextValidationBehavior
                            Flags="ValidateOnValueChanged"
                            x:Name="myTextValidationBehavior"
                            toolkit:MultiValidationBehavior.Error="Entry may not be empty">                            
                        </toolkit:TextValidationBehavior>
                    </Entry.Behaviors>
                </Entry>
            </StackLayout>
        </Grid>
    </StackLayout>

</ContentView>

ContentPage代码(ManageItem.xaml)

<?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.ManageItem"
             Title="My Title">

    <VerticalStackLayout>
        <StackLayout>
            <controls:MyFoodInputControlView NameLabelString="MyLabel1:"
                                               IsOptionalLabelString="Mandatory"
                                               PlaceholderString="e.g. This Placeholder"
                                               EntryInput="{Binding FoodNameString}" />

            <controls:MyFoodInputControlView NameLabelString="MyLable2:"
                                               IsOptionalLabelString="Optional"
                                               PlaceholderString="z.B. This Placeholder" 
                                               EntryInput="{Binding BrandNameString}" />

            <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>

ViewModel代码(ManageItemsViewModel.cs)

namespace MyApp.ViewModels
{
    public partial class ManageItemsViewModel : ObservableObject
    {
        [ObservableProperty]
        private string foodNameString;

        [ObservableProperty]
        private string brandNameString;

        [RelayCommand]
        async Task SaveItem()
        {
            try
            {
                if (!myTextValidationBehavior.IsValid)
                {
                    // 验证失败逻辑
                }

                // 保存逻辑
            }
            catch (Exception e)
            {
                await App.Current.MainPage.DisplayAlert("Error", e.Message, "OK");
            } 
        }

        [RelayCommand]
        async Task CancelItem()
        {
            // 取消逻辑
        }
    }
}

解决方案

直接在ViewModel中引用ContentView内部的myTextValidationBehavior违反了MVVM的分层原则,正确的做法是通过绑定属性将验证状态暴露给外部,再让ViewModel获取该状态。

步骤1:给ContentView添加绑定属性暴露验证状态

在MyFoodInputControlView.xaml.cs中,添加一个绑定属性IsInputValid,并监听内部TextValidationBehavior的IsValid变化来同步值:

using Microsoft.Maui.Controls;
using CommunityToolkit.Maui.Behaviors;

namespace MyApp.Pages.Views;

public partial class MyFoodInputControlView : ContentView
{
    // 暴露输入验证状态的绑定属性
    public static readonly BindableProperty IsInputValidProperty =
        BindableProperty.Create(nameof(IsInputValid), typeof(bool), typeof(MyFoodInputControlView), true);

    public bool IsInputValid
    {
        get => (bool)GetValue(IsInputValidProperty);
        set => SetValue(IsInputValidProperty, value);
    }

    // 其他现有绑定属性(NameLabelString、EntryInput等)保持不变
    public static readonly BindableProperty NameLabelStringProperty =
        BindableProperty.Create(nameof(NameLabelString), typeof(string), typeof(MyFoodInputControlView));

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

    public static readonly BindableProperty EntryInputProperty =
        BindableProperty.Create(nameof(EntryInput), typeof(string), typeof(MyFoodInputControlView));

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

    // 省略其他属性的定义...

    public MyFoodInputControlView()
    {
        InitializeComponent();
        // 监听验证行为的状态变化,同步到绑定属性
        myTextValidationBehavior.PropertyChanged += (sender, e) =>
        {
            if (e.PropertyName == nameof(TextValidationBehavior.IsValid))
            {
                IsInputValid = myTextValidationBehavior.IsValid;
            }
        };
    }
}

步骤2:在ViewModel中绑定验证状态

在ManageItemsViewModel中添加对应属性,用来接收控件的验证状态:

namespace MyApp.ViewModels
{
    public partial class ManageItemsViewModel : ObservableObject
    {
        [ObservableProperty]
        private string foodNameString;

        [ObservableProperty]
        private string brandNameString;

        // 新增:接收食物名称输入的验证状态
        [ObservableProperty]
        private bool isFoodNameValid;

        [RelayCommand]
        async Task SaveItem()
        {
            try
            {
                // 现在可以直接判断验证状态
                if (!IsFoodNameValid)
                {
                    await App.Current.MainPage.DisplayAlert("提示", "食物名称不能为空", "确定");
                    return;
                }

                // 执行保存逻辑
            }
            catch (Exception e)
            {
                await App.Current.MainPage.DisplayAlert("Error", e.Message, "OK");
            } 
        }

        [RelayCommand]
        async Task CancelItem()
        {
            // 取消逻辑
        }
    }
}

步骤3:在ContentPage中关联绑定

修改ManageItem.xaml,给必填的MyFoodInputControlView添加IsInputValid的绑定,设置Mode=OneWayToSource让控件状态同步到ViewModel:

<controls:MyFoodInputControlView NameLabelString="MyLabel1:"
                                   IsOptionalLabelString="Mandatory"
                                   PlaceholderString="e.g. This Placeholder"
                                   EntryInput="{Binding FoodNameString}"
                                   IsInputValid="{Binding IsFoodNameValid, Mode=OneWayToSource}" />

补充说明

  • 如果需要验证多个输入控件,只需给每个控件添加对应的绑定属性和ViewModel属性,然后在SaveItem中逐一判断即可。
  • 这种方式符合MVVM的分层思想,ViewModel不需要直接依赖视图元素,仅通过绑定获取状态,代码更易维护和测试。

内容的提问来源于stack exchange,提问作者OXO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 08:59:14