0

In a .NET MAUI Project, I have a View which contains an Entry with an EntryBehavior having a x:Name="myTextValidationBehavior" which I want to use in one of my ViewModels

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

This ContentView is used in a ContentPage:

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

DataBinding of the "SaveItemCommand", "CancelItemCommand", "FoodNameString" and "BranchNameString" are performed correctly within the ManageItemsViewModel.

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 Canceltem()
        {
            ...
        }
    }
}

In the SaveItemCommand-Handler, I want to access the TextValidationBehavior which was named myTextValidationBehavior in MyFoodInputControlView.

But, I can't reference myTextValidationBehavior within the ManageItemsViewModel. It just does not find it and says The name 'myTextValidationBehavior' does not exist in the current context

How can I reference myTextValidationBehavior?

Tried to reference it in the ViewModel as described above

OXO
  • 391
  • 1
  • 8
  • This violates the entire principal of MVVM. The VM shouldn’t directly reference anything in the View. Instead you can bind the IsValid property to a property in your VM – Jason Feb 18 '23 at 11:29
  • You shouldn't attempt to do that as it would violate MVVM, like Jason wrote. Please read about the [MVVM pattern](https://learn.microsoft.com/en-us/dotnet/architecture/maui/mvvm). There's probably a different way to solve your problem, but for that we need to know what you're actually trying to achieve. – Julian Feb 18 '23 at 12:13
  • @Jason - A violation of the MVVM isn't really what I want then. So, is the x:Name="..." reference just meant to be for use in its own Code-Behind? (with own I mean the Code-Behind of the View in my case) – OXO Feb 19 '23 at 05:15
  • @ewerspej - I have a ContentPage using a couple of the above ContentViews in its XAML. Below these ContentViews I have a SaveItem-Button and a CancelItem-Button. Once the SaveItem-Button is clicked, I need to evaluate the Entry-Controls of the different ContentViews if they have a Value or if the Value is appropriate before I can save the Entry-Values in a database. The Entry-Values itself are Bound to the VM of the ContentPage and can be evaluated there. Question is more or less, how I can bind the IsValue state of the TextValidationBehavior to this VM and where it should have its Code-Behind – OXO Feb 19 '23 at 05:21
  • @ewerspej - Additionally, I want to display an Icon with an exclamation mark or something like that in a Label within the ContentView. So, I wanted to reference this Label in the VM of the Parent ContentPage, too. It is more or less like a thinking we had in Windows-Forms where you could directly do things like that in the Button_Click-Event and could reference the UI-Elements to set something or to draw a red border around the Element having a problem. And in my case, it would be nice to set the Focus into the first Entry causing the IsValid=false so the user can directly go an change value – OXO Feb 19 '23 at 05:33

0 Answers0