Search code examples
c#xamlmvvmmauicommunity-toolkit-mvvm

.Net Maui Switch using MVVM Community ToolKit return Object Sender to View Model


I have multiple Switches in a Xaml page and I am struggling to grasp the concept of MVVM when using Switches and handling State Changes etc. I am trying within a view model to capture the object and argument within the ViewModel which is available within the xaml.cs file.

A standard Switch Xaml from Microsoft on Switches.

<Switch Toggled="OnToggled" />

The same page Xaml.cs File

void OnToggled(object sender, ToggledEventArgs e)
{
    // I have the sender so can target the switch now and change values colours etc.
}

Now it is this massive cough for me leap into Mvvm which I am failing to grasp.

I have followed every single guide/demo/tutorial on Mvvm but I can not figure out how doing the near same thing using Maui Community Toolkit and using a View Model I can cut out the Xaml.cs element of my code. As I believe the page should not be aware of the View vice versa.

My current code is as follows :- SettingsPage.xaml

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyProject.Views.SettingsPage"
             xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             xmlns:vm="clr-namespace:MyProject.ViewModels"
             x:DataType="vm:SettingsPageViewModel"
             BackgroundColor="{DynamicResource PageBackGround}">

    <ContentPage.Content>
        <StackLayout>
            <Switch IsToggled = "True"
                <Switch.Behaviors>
                    <mct:EventToCommandBehavior
                        x:TypeArguments="x:Object"
           EventName="Toggled"
           Command="{Binding ToggledCommand}" />
                </Switch.Behaviors>
            </Switch>              
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

SettingsPage.xaml.cs

namespace MyProject.Views;

public partial class SettingsPage : ContentPage
{
    ILogger<SettingsPage> _logger;
    public SettingsPage(SettingsPageViewModel settingsPageViewModel, ILogger<SettingsPage> logger)
    {
        InitializeComponent();
        BindingContext = settingsPageViewModel;

        _logger = logger;
        _logger.LogInformation("Navigation to Settings Page.");
    }
}

SettingsPageViewModel.cs

namespace MyProject.ViewModels
{
    public partial class SettingsPageViewModel : BaseViewModel
    {
        ILogger<SettingsPageViewModel> _logger;
        LogController LogController;
        public SettingsPageViewModel(ILogger<SettingsPageViewModel> logger)
        {
            _logger = logger;
            LogController = new LogController();
        }

        // Here I want to capture the object so that I can have multiple switches on the page and be able to identify them to change values etc for what states they are in.
        [RelayCommand]
        public void Toggled(ToggledEventArgs e) 
        {
            var bangingMyheadAgainstAWall = "e";
        }
    }       
}

I have also tried without using the EventToCommandBehaviour and just used standard Toggled, Istoggled, OnToggled, IWishIknewWhichSwitchWasToggled but I just can not get the properties through to the view model or I have backed myself in to a corner and am a little confused.

Any help/ push in the correct direction to help me handle this situation correctly would be greatly appreciated. Thanks in Advance.


Solution

  • It seems like you're overcomplicating things. You can forget mostly about events and getting/setting values that way. The key here is data binding.

    IsToggled, like most properties in .NET MAUI, is a bindable property. This means that you can bind a property from your view model to it, and the control will update that property whenever something changes, no event needed.

    You're mostly there with your code though! You can remove the event to command stuff, you don't need it. Also remove

    Change your Switch to: <Switch IsToggled = "{Binding MyProperty}"/>

    And on your SettingsPageViewModel add a property like this, this is assuming the use of the MVVM Toolkit:

    [ObservableProperty]
    private bool myProperty;
    

    Now whenever the switch is toggled, the property in code should reflect the new value and vice versa.

    From what I understand that you're doing is your thought process was: I need an event to catch the switch being toggled, but that's not MVVM, so I need a Command to do the same thing.

    Usually that's not the case. A Command really only is for executing logic, not setting or retrieving control values.

    If I can offer a last piece of unsolicited advice: if you're just starting out with MVVM, try doing so without the Toolkit. I love the MVVM Toolkit, it's amazing, but it also has a lot of magic. If you know your way around MVVM it's a productivity boost and can be really helpful. If you're just starting, it will only add to the confusion.