Search code examples
mauidatatemplate

Accessing Controls of a DataTemplate with underlying ContentView hosting the Controls?


I use a SharpNado CollectionView in .NET MAUI with a DataTemplate as can be seen below.

There is also a Button which has its Button_Clicked-Event in the Code-Behind file. From there, I wanted to evaluate each MinEntry and MaxEntry that is displayed in CollectionView. There should be an evaluation like MinEntry-Value should always greater or equal to MaxEntry-Value, also that there are values entered at all.

My current problem is, how I could access the list of all MinEntrys and MaxEntrys? Currently, I am not able to get these Controls at all. I tried several ways with FindByName etc., but I always got "null" as the FindByName-Result.

How could I access and evaluate these Controls?

<?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:viewModels="clr-namespace:MyApp.ViewModels"
             xmlns:sho="http://sharpnado.com"             
             x:DataType="viewModels:MyViewViewModel"
             x:Class="MyApp.Pages.Views.MyView">

    <ContentView.Resources>
        <ResourceDictionary>

            <DataTemplate x:Key="VerticalItemTemplate" x:DataType="{x:Type models:MySelection}">
                <sho:DraggableViewCell x:Name="DraggableViewCell">
                    <ContentView x:Name="DraggableContentView">
                       <SwipeView>

                            <Frame HeightRequest="60" Padding="15, 5, 15, 0">
                                <Grid RowDefinitions="Auto" ColumnDefinitions="120, Auto, Auto, Auto, Auto, 70, Auto">
                                    <Label Grid.Column="0" Text="{Binding Name}" VerticalOptions="CenterAndExpand"/>

                                    <Entry Grid.Column="1" Placeholder="0" Text="{Binding Min, Mode=TwoWay}" VerticalOptions="Center" HorizontalTextAlignment="Center" TextChanged="Entry_TextChanged" x:Name="MinEntry"/>
                                    
                                    <Entry Grid.Column="3" Placeholder="100" Text="{Binding Max, Mode=TwoWay}" VerticalOptions="Center" HorizontalTextAlignment="Center" TextChanged="Entry_TextChanged"  x:Name="MaxEntry"/>
                                    
                                    <Label Grid.Column="5" Text="0" VerticalOptions="Center" HorizontalOptions="EndAndExpand"/>                             
                                </Grid>
                            </Frame>
                            
                            ...
                        </SwipeView>
                    </ContentView>
                </sho:DraggableViewCell>
            </DataTemplate>
            
        </ResourceDictionary>
    </ContentView>
    
    <StackLayout>
            
        <sho:CollectionView x:Name="CollectionView"
                            CollectionPadding="10,10,10,10"
                            CurrentIndex="{Binding CurrentIndex}"
                            EnableDragAndDrop="True"
                            DragAndDropDirection="VerticalOnly"
                            DragAndDropTrigger="LongTap"
                            ItemHeight="60"
                            ItemsSource="{Binding SelectedItems, Mode=OneWay}"
                            ItemTemplate="{StaticResource VerticalItemTemplate}"
                            CollectionLayout="Vertical" />
        
    </StackLayout>

</ContentView>

Solution

  • My current problem is, how I could access the list of all MinEntrys and MaxEntrys? Currently, I am not able to get these Controls at all. I tried several ways with FindByName etc., but I always got "null" as the FindByName-Result.

    We usually use Data binding and MVVM to achieve this.

    We can add two fields (e.g. MinValue and MaxValue) to the Item model and implement interface INotifyPropertyChanged .While changing the value of the two fields in the UI, the background value (MinValue and MaxValue) will also change.

    I have created a demo based on the CollectionView on maui.

    You can refer to the following code:

    1.create item model ItemModel.cs

    public class ItemModel: INotifyPropertyChanged 
    {
        public string Name { get; set; }
        public string Description { get; set; }
    
        //public int MinValue { get; set; }
        private int minValue;
        public int MinValue
        {
            get => minValue;
            set
            {
                SetProperty(ref minValue, value);
            }
        }
    
    
        //public int MaxValue { get; set; }
        private int maxValue;
        public int MaxValue
        {
            get => maxValue;
            set
            {
                SetProperty(ref maxValue, value);
            }
        }
    
        bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (Object.Equals(storage, value))
                return false;
            storage = value;
            OnPropertyChanged(propertyName);
            return true;
        }
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    
    }
    

    2.create a ViewModel MyViewModel.cs

    public class MyViewModel 
    {
        public ObservableCollection<ItemModel> Items { get; set; }
    
        public ICommand GetResultCommand { get; set; }
    
    
        public MyViewModel()
        {
    
            Items = new ObservableCollection<ItemModel>();
    
            Items.Add(new ItemModel { Name = "test1", Description = "Description 1" });
            Items.Add(new ItemModel { Name = "test2", Description = "Description 2" });
            Items.Add(new ItemModel { Name = "test3", Description = "Description 3" });
    
            GetResultCommand = new Command(GetResult);
    
        }
    
        private void GetResult()
        {
            foreach (var item in Items)
            {
                System.Diagnostics.Debug.WriteLine("--->The result is: " + item.Name+ "Min Value = " + item.MinValue +" <--> MaxValue = " + item.MaxValue);
            }
        }
    }
    

    3.Usage example:

    <?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"
                 x:Class="MauiMvvmApp226.CollectionViewPage"
                 xmlns:MauiMvvmApp="clr-namespace:MauiMvvmApp226"
                 Title="CollectionViewPage">
    
        <ContentPage.BindingContext>
            <MauiMvvmApp:MyViewModel></MauiMvvmApp:MyViewModel>
        </ContentPage.BindingContext>
    
        <ContentPage.Resources>
            <ResourceDictionary>
                <DataTemplate x:Key="personTemplate">
                        <HorizontalStackLayout  >
                            <StackLayout Orientation="Vertical">
                                <Label Text="{Binding Name}" FontSize="Title" />
                                <Label Text="{Binding Description}" FontSize="Subtitle"/>
                            </StackLayout>
    
                            <Label Text="Min:" Margin="10,0,10,0"></Label>
                            <Entry Text="{Binding MinValue}"   WidthRequest="60"></Entry>
                                
                            <Label Text="Max:" Margin="10,0,10,0"></Label>
                            <Entry Text="{Binding MaxValue}"  WidthRequest="60"></Entry>
                    </HorizontalStackLayout>
                </DataTemplate>
            </ResourceDictionary>
        </ContentPage.Resources>
        <VerticalStackLayout>
            
            <Button  Text="Result" Command="{Binding GetResultCommand}"  HorizontalOptions="FillAndExpand" Margin="10"/>
            
            <CollectionView  ItemsSource="{Binding Items}" ItemTemplate="{StaticResource personTemplate}" x:Name="mCollectionView" >
            </CollectionView>
    
        </VerticalStackLayout>
    </ContentPage>