button doesn't work with command

Eduardo Gomez Romero 465 Reputation points
2024-07-11T21:16:12.93+00:00

I have a custom command

public partial class DateTimeZonePicker : ContentView {

    public DateTimeZonePicker() {
        InitializeComponent();
    }


    public static readonly BindableProperty OpenDateTimePickerCommndProperty = BindableProperty.Create(
    nameof(OpenDateTimePickerCommnd), typeof(RelayCommand), typeof(DateTimeZonePicker));

    public RelayCommand OpenDateTimePickerCommnd {
        get => (RelayCommand)GetValue(OpenDateTimePickerCommndProperty);
        set => SetValue(OpenDateTimePickerCommndProperty, value);
    }

    public static readonly BindableProperty IsDateTimePickerVisibleProperty = BindableProperty.Create(
    nameof(IsDateTimePickerVisible), typeof(bool), typeof(DateTimeZonePicker));

    public bool IsDateTimePickerVisible {
        get => (bool)GetValue(IsDateTimePickerVisibleProperty);
        set => SetValue(IsDateTimePickerVisibleProperty, value);
    }


    public static readonly BindableProperty TimezonesProperty = BindableProperty.Create(
        nameof(Timezones), typeof(List<string>), typeof(DateTimeZonePicker));

    public List<string> Timezones {
        get => (List<string>)GetValue(TimezonesProperty);
        set => SetValue(TimezonesProperty, value);
    }

    public static readonly BindableProperty SelectedDateTimeProperty = BindableProperty.Create(
      nameof(SelectedDateTime), typeof(DateTime), typeof(DateTimeZonePicker), null,
      BindingMode.TwoWay);

    public DateTime SelectedDateTime {
        get => (DateTime)GetValue(SelectedDateTimeProperty);
        set => SetValue(SelectedDateTimeProperty, value);
    }

    public static readonly BindableProperty SelectedTimeZoneProperty = BindableProperty.Create(
        nameof(SelectedTimeZone), typeof(string), typeof(DateTimeZonePicker), null,
        BindingMode.TwoWay);

    public string SelectedTimeZone {
        get => (string)GetValue(SelectedTimeZoneProperty);
        set => SetValue(SelectedTimeZoneProperty, value);
    }

    public static readonly BindableProperty OkButtonClickedCommandProperty = BindableProperty.Create(
        nameof(OkButtonClickedCommand), typeof(RelayCommand), typeof(DateTimeZonePicker));

    public RelayCommand OkButtonClickedCommand {
        get => (RelayCommand)GetValue(OkButtonClickedCommandProperty);
        set => SetValue(OkButtonClickedCommandProperty, value);
    }


    public static readonly BindableProperty CancelButtonClickedCommandProperty = BindableProperty.Create(
        nameof(CancelButtonClickedCommand), typeof(RelayCommand), typeof(DateTimeZonePicker));

    public RelayCommand CancelButtonClickedCommand {
        get => (RelayCommand)GetValue(CancelButtonClickedCommandProperty);
        set => SetValue(CancelButtonClickedCommandProperty, value);
    }

    public static readonly BindableProperty ButtonTextProperty = BindableProperty.Create(
       nameof(ButtonText), typeof(string), typeof(DateTimeZonePicker));

    public string ButtonText {
        get => (string)GetValue(ButtonTextProperty);
        set => SetValue(ButtonTextProperty, value);
    }

    public static readonly BindableProperty IsButtonEnabledProperty = BindableProperty.Create(
        nameof(IsButtonEnabled), typeof(bool), typeof(DateTimeZonePicker));

    public bool IsButtonEnabled {
        get => (bool)GetValue(IsButtonEnabledProperty);
        set => SetValue(IsButtonEnabledProperty, value);
    }


    public static readonly BindableProperty ButtnClickCommandProperty = BindableProperty.Create(
        nameof(ButtnClickCommand), typeof(RelayCommand), typeof(DateTimeZonePicker));

    public RelayCommand ButtnClickCommand {
        get => (RelayCommand)GetValue(ButtnClickCommandProperty);
        set => SetValue(ButtnClickCommandProperty, value);
    }

}


<Grid
    Margin="20"
    ColumnDefinitions="*,*"
    RowDefinitions="350,60,*">
    <Label Text="Select date an time" />
    <Label
        Grid.Column="1"
        FontFamily="Mat"
        FontSize="32"
        HorizontalTextAlignment="End"
        Text="{Static icon:IconFont.Date_range}">
        <Label.Behaviors>
            <mct:TouchBehavior Command="{Binding OpenDateTimePickerCommnd, Source={x:Reference DateTmeZone}}" />
        </Label.Behaviors>
    </Label>
    <picker:SfDateTimePicker
        Grid.Column="1"
        DateFormat="dd_MMM_yyyy"
        HeightRequest="350"
        HorizontalOptions="End"
        IsVisible="{Binding IsDateTimePickerVisible, Source={x:Reference DateTmeZone}}"
        MinimumDate="{Static sys:DateTime.Now}"
        SelectedDate="{Binding SelectedDateTime, Mode=TwoWay, Source={x:Reference DateTmeZone}}"
        TimeFormat="HH_mm"
        VerticalOptions="Start"
        WidthRequest="350">
        <picker:SfDateTimePicker.HeaderView>
            <picker:DateTimePickerHeaderView
                DateFormat="MMM/dd/yyyy"
                TimeFormat="HH:mm" />
        </picker:SfDateTimePicker.HeaderView>
        <picker:SfDateTimePicker.FooterView>
            <picker:PickerFooterView
                Height="40"
                OkButtonText="Select date"
                ShowOkButton="True" />
        </picker:SfDateTimePicker.FooterView>
        <picker:SfDateTimePicker.Behaviors>
            <mct:EventToCommandBehavior
                Command="{Binding OkButtonClickedCommand, Source={x:Reference DateTmeZone}}"
                EventName="OkButtonClicked" />
            <mct:EventToCommandBehavior
                Command="{Binding CancelButtonClickedCommand, Source={x:Reference DateTmeZone}}"
                EventName="CancelButtonClicked" />
        </picker:SfDateTimePicker.Behaviors>
    </picker:SfDateTimePicker>
    <Label
        Grid.Row="1"
        Text="Time Zone"
        VerticalTextAlignment="Center" />
    <Picker
        Title="Choose your timezone"
        Grid.Row="1"
        Grid.Column="1"
        FontAttributes="Bold"
        ItemsSource="{Binding Timezones, Source={x:Reference DateTmeZone}}"
        SelectedItem="{Binding SelectedTimeZone, Mode=TwoWay, Source={x:Reference DateTmeZone}}" />
    <Button
        Grid.Row="2"
        Grid.ColumnSpan="2"
        IsEnabled="{Binding IsButtonEnabled, Source={x:Reference DateTmeZone}}"
        Text="{Binding ButtonText, Source={x:Reference DateTmeZone}}"
        Command="{Binding ButtnClickCommand, Source={x:Reference DateTmeZone}}"
        VerticalOptions="EndAndExpand" />
</Grid>


Usage

<ContentPage
    x:Class="DemyAI.Views.ScheduleLecturePage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:contols="clr-namespace:DemyAI.Controls"
    xmlns:controls="clr-namespace:DemyAI.Controls"
    xmlns:editors="clr-namespace:Syncfusion.Maui.Inputs;assembly=Syncfusion.Maui.Inputs"
    xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
    xmlns:picker="clr-namespace:Syncfusion.Maui.Picker;assembly=Syncfusion.Maui.Picker"
    xmlns:skia="clr-namespace:SkiaSharp.Extended.UI.Controls;assembly=SkiaSharp.Extended.UI"
    xmlns:vm="clr-namespace:DemyAI.ViewModels"
    x:DataType="vm:ScheduleLecturePageViewModel">
    <ContentPage.Behaviors>
        <mct:EventToCommandBehavior
            Command="{Binding AppearingCommand}"
            EventName="Appearing" />
    </ContentPage.Behaviors>
    <contols:DateTimeZonePicker
        ButtnClickCommand="{Binding ScheduleButtonClickedCommand}"
        ButtonText="{Binding ButtonText}"
        CancelButtonClickedCommand="{Binding CancelButtonClickedCommand}"
        IsButtonEnabled="{Binding IsButtonEnabled}"
        IsDateTimePickerVisible="{Binding IsDateTimeZonePickerVisible}"
        OkButtonClickedCommand="{Binding OkButtonClickedCommand}"
        OpenDateTimePickerCommnd="{Binding OpenDateTimePickerCommand}"
        SelectedDateTime="{Binding SelectedDateTime}"
        SelectedTimeZone="{Binding SelectedTimeZone}"
        Timezones="{Binding Timezones}" />
</ContentPage>


public partial class ScheduleLecturePageViewModel(IAppService appService,
    IHttpService httpService,
    IDataService<DemyUser> dataService,
    IMeetingService meetingServic) : BaseViewModel {
    [ObservableProperty]
    bool isDateTimeZonePickerVisible;
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(ButtonText), nameof(IsButtonEnabled))]
    DateTime? selectedDateTime = null;
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(IsButtonEnabled))]
    String selectedTimeZone;
    [ObservableProperty]
    public List<string> timezones;
    public string ButtonText => SelectedDateTime.HasValue ? $"Schedule for {SelectedDateTime:MMMM dd yyyy 'at' HH:mm}" : "";
    public bool IsButtonEnabled => SelectedDateTime.HasValue && !string.IsNullOrEmpty(SelectedTimeZone);
    [RelayCommand]
    void Appearing() {
        Timezones = TimeZoneService.GetTimeZones();
    }
    [RelayCommand]
    void OpenDateTimePicker() {
        IsDateTimeZonePickerVisible = true;
    }
    [RelayCommand]
    void OkButtonClicked() {
        IsDateTimeZonePickerVisible = false;
    }
    [RelayCommand]
    void CancelButtonClicked() {
        IsDateTimeZonePickerVisible = false;
    }
    [RelayCommand]
    async Task ScheduleButtonClickedAsync() {
        if (appService != null) {
            await appService.DisplayToast($"You have a meeting on {SelectedDateTime}",
                ToastDuration.Short, 14);
        }
    }
}

everything is working, but the button dissent wants to work

User's image

I bound to the button, but it doesn't work

.NET MAUI
.NET MAUI
A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
3,460 questions
0 comments No comments
{count} votes

Accepted answer
  1. Leon Lu (Shanghai Wicresoft Co,.Ltd.) 75,036 Reputation points Microsoft Vendor
    2024-07-12T03:02:42.3+00:00

    Hello,

    When you use the [RelayCommand] attribute to auto-generate a Command for a method, it depends on the method's return type and signature what type of Command will be generated.

    Your method is of return type async Task, it will create an AsyncRelayCommand .

    We you need to change type of ButtnClickCommand from RelayCommand to AsyncRelayCommand like following code in the DateTimeZonePicker's background code .

    public static readonly BindableProperty ButtnClickCommandProperty = BindableProperty.Create(
         nameof(ButtnClickCommand), typeof(AsyncRelayCommand), typeof(DateTimeZonePicker));
     
    public AsyncRelayCommand ButtnClickCommand
    {
         get => (AsyncRelayCommand)GetValue(ButtnClickCommandProperty);
         set => SetValue(ButtnClickCommandProperty, value);
    }
    

    Or you still use RelayCommand by changing a ScheduleButtonClickedAsync method's return type from Task to void

     [RelayCommand]
        async void ScheduleButtonClickedAsync() {
            if (appService != null) {
                await appService.DisplayToast($"You have a meeting on {SelectedDateTime}",
                    ToastDuration.Short, 14);
            }
        }
    

    And change the value of ButtnClickCommand to ScheduleButtonClickedAsyncCommand in the DateTimeZonePicker

     <contols:DateTimeZonePicker
            ButtnClickCommand="{Binding ScheduleButtonClickedAsyncCommand}"
    ...      
     />
    

    Best Regards,

    Leon Lu


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.