Search code examples
c#xamluwp-xamlwinui-3

WinUI3: How to reference controls in viewmodel?


I'm using TemplateStudio to build my project

In Views > TestPage.xaml

<Page
    x:Class="FluentQQ.Views.TestPage"
    ...>

    <Grid>
        <TextBox x:Name="MessageInput" />
    </Grid>
</Page>

And in Views > TestPage.xaml.cs

using FluentQQ.ViewModels;
using Microsoft.UI.Xaml.Controls;

namespace FluentQQ.Views;

public sealed partial class TestPage : Page
{
    public TestViewModel ViewModel
    {
        get;
    }

    public TestPage()
    {
        ViewModel = App.GetService<TestViewModel>();
        InitializeComponent();
    }
}

Then, I tried to get the contents of the TextBox "MessageInput"
So, in ViewModels > TestViewModel.cs, I use

MessageInput.Text

But it dosen't work

CS0103  The name 'MessageInput' does not exist in the current context

I know this question may very simple,but forgive me for just being a beginner


Solution

  • As the error message indicates, the MessageInput control does not exits in *TestPageViewModel. With MVVM, usually, you should use bindings to get data from your view.

    Just to make sure we are on the same page, in this case:

    • TestPage.xaml is the View
    • TestPage.xaml.cs is the code-behind
    • TestPageViewModel.cs is the ViewModel
    1. Install the CommunityToolkit.Mvvm nuget package. This will make your life easier if you are using the MVVM pattern.

    2. In your ViewModel, TestPageViewModel:

    // This class needs to be "partial" 
    // for the "CommunityToolkit.Mvvm" source generators.
    public partial class TestPageViewModel : ObservableObject
    {
        // The source generators will create 
        // an UI interactable "SomeText" property for you.
        [ObservableProperty]
        private string someText;
    }
    
    1. In your code-behind, TestPage.xaml.cs:
    public sealed partial class TestPage : Page
    {
        public TestViewModel ViewModel { get; }
    
        public TestPage()
        {
            ViewModel = App.GetService<TestViewModel>();
            InitializeComponent();
        }
    }
    
    1. Then in your view, TestPage.xaml:
    <TextBox
        x:Name="MessageInput"
        Text="{x:Bind ViewModel.SomeText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    

    That's all. SomeText will be updated every time you change the text in the TextBox.

    By the way, you can access the TextBox directly from code-behind. Just make sure you use x:Name to name it.

    TestPage.xaml.cs

    MessageInput.Text = "some text";