.netfunctionbindingmauicontentview

Functions as Bindable properties in .NET MAUI ContentView


Can a Bindable property in a ContentView be of type Func<bool>? That is, something like this:

public partial class MyControl : ContentView
{
    public static readonly BindableProperty DoSomethingProperty = BindableProperty.Create(
            nameof(DoSomething),
            typeof(Func<bool>),
            typeof(MyControl);

    public Func<bool> DoSomething
    {
        get => (Func<bool>)GetValue(DoSomethingProperty);
        set => SetValue(DoSomethingProperty, value);
    }
}

Then you could use it in a page like such:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:MauiPlayground.Controls"
             x:DataType="vm:MainPageViewModel"
             x:Class="MauiPlayground.MainPage">
    <ContentPage.Content>
        <VerticalStackLayout>
            <controls:MyControl DoSomething="{Binding ViewModelDoSomething}" />
        </VerticalStackLayout>
    </ContentPage.Content>
</ContentPage>

And the MainPageViewModel would contain this method:

public bool ViewModelSoSomething()
{
    return true;
}

(This isn't actual code, just wondering if this can be done in theory. If, for example, you want to pass a callback function or method to the ContentView)

I tried doing something like this and the compiler didn't complain, but the value of the DoSomething property was never set. Maybe there's another way of doing this?


Solution

  • You can achieve this by adding BindableProperty of type ICommand to your ContentView and you can also pass data to the command by adding BindableProperty of type object.

    I achieved this function on my side,And I also added a common property YourName to my ContentView.

    Please refer to the following code:

    MyControl.xaml

    public partial class MyControl : ContentView 
    {
        public String YourName
        {
            get
            {
                String value = (String)GetValue(YourNameProperty);
                return value;
            }
            set
            {
                SetValue(YourNameProperty, value);
            }
        }
    
        public static readonly BindableProperty YourNameProperty = BindableProperty.Create(nameof(YourName)
        , typeof(String)
        , typeof(MyControl), defaultBindingMode: BindingMode.TwoWay, propertyChanged: OnYourNameChanged);
    
        static void OnYourNameChanged(BindableObject bindable, object oldValue, object newValue)
        {
            Console.WriteLine("-----------------> " + newValue);
        }
    
       // add BindableProperty:ChildCommandProperty
    
        public static readonly BindableProperty ChildCommandProperty =
                BindableProperty.Create(nameof(ChildCommand), typeof(ICommand), typeof(MyControl));
    
        public ICommand ChildCommand
        {
            get => (ICommand)GetValue(ChildCommandProperty);
            set => SetValue(ChildCommandProperty, value);
        }
    
    
       // add BindableProperty:ChildCommandParameterProperty
    
        public static BindableProperty ChildCommandParameterProperty =
            BindableProperty.Create(nameof(ChildCommandParameter), typeof(object), typeof(MyControl));
    
        public object ChildCommandParameter
        {
            get => (object)GetValue(ChildCommandParameterProperty);
            set => SetValue(ChildCommandParameterProperty, value);
        }
    
        public MyControl()
          {
                InitializeComponent();
          }
    }
    

    MyControl.xaml.cs

    <?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"
                 x:Class="MauiMyContentViewApp.Controls.MyControl"
                 
                   x:Name="TestControlView"
                 >
        <ContentView.Content>
            <VerticalStackLayout>
                <Label   Text="{Binding Source={x:Reference TestControlView}, Path=YourName}" x:Name="NameLabel"  Margin="10"
                VerticalOptions="Center" 
                HorizontalOptions="Center" />
    
    
                <Button Text="Do Something"
                    Command="{Binding Source={x:Reference TestControlView}, Path= ChildCommand}"  
                    CommandParameter="{Binding Source={x:Reference TestControlView}, Path= ChildCommandParameter}"
                     />
            </VerticalStackLayout>
        </ContentView.Content>
    </ContentView>
    

    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="MauiMyContentViewApp.MainPage"
                 xmlns:controls="clr-namespace:MauiMyContentViewApp.Controls"
                 xmlns:viewmodels="clr-namespace:MauiMyContentViewApp.ViewModels"
                 x:Name="mainpage"
                 >
    
        <ContentPage.BindingContext>
            <viewmodels:TestViewModel></viewmodels:TestViewModel>
        </ContentPage.BindingContext>
    
            <VerticalStackLayout
                Padding="30,0"
                Spacing="25">
                <controls:MyControl BackgroundColor="Yellow"  YourName="HanMeimei"
                                   ChildCommand="{Binding DoSomethingCommand}"
                                   ChildCommandParameter = "test123"
                                   >
                </controls:MyControl>
            </VerticalStackLayout>
    </ContentPage>
    

    TestViewModel.cs

    public class TestViewModel
    {
    
        public ICommand DoSomethingCommand => new Command(doSomethingMethod);
    
        private void doSomethingMethod(object obj)
        {
            System.Diagnostics.Debug.Write("----->do something and the passed parameter is : " + obj.ToString());
        }
    
    
    }