简体   繁体   中英

WPF - MVVM - UserControl binding

I'm trying to realize a simple example of a UserControl, showing in a TextBox the current DateTime, updated four times each second.

I create a simple user control:

<UserControl x:Class="UC.TestUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:UC"
             mc:Ignorable="d" 
             d:DesignHeight="50" d:DesignWidth="100">
    <d:UserControl.DataContext>
        <local:TestUC_VM/>
    </d:UserControl.DataContext>
    <Grid Background="Azure">
        <TextBox Text="{Binding TestString}"/>
    </Grid>
</UserControl>

Where its ViewModel is:

namespace UC
{
    public class TestUC_VM : INotifyPropertyChanged
    {
        private string _testString;
        public string TestString
        {
            get => _testString;
            set
            {
                if (value == _testString) return;
                _testString = value;
                OnPropertyChanged();
            }
        }

        public TestUC_VM()
        {
            TestString = "Test string.";
        }

        public event PropertyChangedEventHandler PropertyChanged;
        void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

MainWindow XAML:

<Window x:Class="UC.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:UC"
        mc:Ignorable="d"
        Title="MainWindow" Height="100" Width="200">
    <Window.DataContext>
        <local:MainWindow_VM/>
    </Window.DataContext>
    <Window.Resources>
        <local:TestUC_VM x:Key="TestUC_VM"/>
    </Window.Resources>
    <Grid>
        <local:TestUC DataContext="{StaticResource TestUC_VM}"/>
    </Grid>
</Window>

And its ViewModel:

namespace UC
{
    public class MainWindow_VM
    {
        public TestUC_VM _uc_VM;

        public MainWindow_VM()
        {
            _uc_VM = new TestUC_VM();
            Task.Run(() => ChangeString());
        }

        public async Task ChangeString()
        {
            while (true)
            {
                _uc_VM.TestString = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                await Task.Delay(250);
            }
        }
    }
}

Even though I see with debugger that I'm passing through the TestString setter, the MainWindow is not updated. I'm quite sure I'm missing something trivial in setting DataContext of UC in MainWindow, but I've not been able to find what after several hours of browsing and thinking.

Any help appreciated.

The expression

<local:TestUC DataContext="{StaticResource TestUC_VM}"/>

assigns the value of the TestUC_VM resource to the UserControl's DataContext. This is a different object than the _uc_VM member of the main view model, which you are later updating.

Turn the member into a public property

public TestUC_VM UcVm { get; } = new TestUC_VM();

and write

<local:TestUC DataContext="{Binding UcVm}"/>

Update the view model like this:

UcVm.TestString = ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM