Home > Software design >  How can I modify a UIElement.property from another class?
How can I modify a UIElement.property from another class?

Time:10-11

I'm working on a WinUI app (c# and xaml) with multiple frames and pages. The problem is that I need to modify a UIElement property (TextBox.Text) from another class. I've been trying so many things and none of them has worked yet. I'd be glad if someone could inspire me with some useful ways to do it. It can be anything aside from xaml data binding (<property={"Binding bindingName"}).

Thanks for the help.

CodePudding user response:

In this sample code, I have 2 pages (Page1 and Page2) and 1 ViewModel (MainViewModel). Each page has a TextBox that are bound to the same property in the MainViewModel.

If you change the text in Page1, the text in Page2 will be changed, and vice versa.

NuGet packages

App.xaml.cs

using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;

namespace MultiplePagesSingleViewModel;

public partial class App : Application
{
    private Window? window;

    public App()
    {
        this.InitializeComponent();
        Ioc.Default.ConfigureServices(
            new ServiceCollection()
            // This needs to be Singleton
            .AddSingleton<MainViewModel>()
            .BuildServiceProvider());
    }

    protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
    {
        this.window = new MainWindow();
        this.window.Activate();
    }
}

Page1.xaml

<Page
    x:Class="MultiplePagesSingleViewModel.Page1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:MultiplePagesSingleViewModel"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">

    <StackPanel>
        <TextBlock Text="Page 1" />
        <TextBox Text="{x:Bind ViewModel.SomeText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </StackPanel>

</Page>

Page1.xaml.cs

using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.UI.Xaml.Controls;

namespace MultiplePagesSingleViewModel;

public sealed partial class Page1 : Page
{
    public Page1()
    {
        this.InitializeComponent();
        // This MainViewModel is the same instance that Page2 gets.
        ViewModel = Ioc.Default.GetRequiredService<MainViewModel>();
    }

    public MainViewModel ViewModel { get; }
}

Page2.xaml

<Page
    x:Class="MultiplePagesSingleViewModel.Page2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:MultiplePagesSingleViewModel"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">

    <StackPanel>
        <TextBlock Text="Page 2" />
        <TextBox Text="{x:Bind ViewModel.SomeText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </StackPanel>

</Page>

Page2.xaml.cs

using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.UI.Xaml.Controls;

namespace MultiplePagesSingleViewModel;

public sealed partial class Page2 : Page
{
    public Page2()
    {
        InitializeComponent();
        // This MainViewModel is the same instance that Page1 gets.
        ViewModel = Ioc.Default.GetRequiredService<MainViewModel>();
    }

    public MainViewModel ViewModel { get; }
}

MainViewModel.cs

using CommunityToolkit.Mvvm.ComponentModel;

namespace MultiplePagesSingleViewModel;

// This class needs to be "partial" for CommunityToolkit.Mvvm.
public partial class MainViewModel : ObservableObject
{
    [ObservableProperty]
    // The CommunityToolkit.Mvvm will automatically generate
    // a UI-Interactive "SomeText" property for you.
    private string someText = "Default text";
}

MainWindow.xaml

<Window
    x:Class="MultiplePagesSingleViewModel.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:MultiplePagesSingleViewModel"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid ColumnDefinitions="*,*">
        <local:Page1 Grid.Column="0" />
        <local:Page2 Grid.Column="1" />
    </Grid>

</Window>

CodePudding user response:

Well, finally after two weeks of research I've found and check a solution.

The solution is basically rising and catching events from the different classes. I found this information in a MSDN post. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/how-to-publish-events-that-conform-to-net-framework-guidelines

This post is REALLY STRAIGHT FORWARD. I've created the CustomEventArgs class and then the publisher class is my controller (.cs) and my subscriber is the model (.xaml.cs). The only problem that I've encountered is setting alll the methods and attributes as static in order to be able to call the controller function from other models. The problem is that on the raiseEvent(this, e); in the publisher class, this cannot be static so i've written null instead.

Also, I'd like to say that it works extremely fluent and with no lag or delay at all even if I constantly use it.

I hope this helps to everybody encountering the same problem.

  • Related