c# - 使用 WPF 数据绑定(bind)设计响应式 UI

标签 c# wpf multithreading data-binding

我是 WPF 新手。我正在尝试使用 WPF 绑定(bind)来理解 MVVM 模式。我有以下 2 门类(class)

  1. MainWindow.xamal
  2. View 模型

    我有三个控件

    1. 显示 ViewModel 的“Name”属性的文本框
    2. 显示 ViewModel 的“状态”依赖属性的文本框
    3. 调用“ViewModel”类的“Execute”方法的按钮。

    现在,Execute() 方法有点庞大,因此我创建了一个委托(delegate)并异步调用它。但我的 UI 仍然被阻止,并且它没有更新“状态”依赖属性的值

请参阅以下类(class)。

应用程序.xaml.cs

namespace bindingDemo
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            MainWindow mw = new MainWindow();
            ViewModel vm = new ViewModel();

            ///Set data context property of main windows.
            mw.DataContext = vm;
            mw.Show();
        }
    }
}

MainWindow.xaml

<Window x:Class="bindingDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <TextBox Text="{Binding Name, Mode=TwoWay}"   Height="23" HorizontalAlignment="Left" Margin="76,26,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
    <Button Command="{Binding Path=MyCommand}" Content="Button" Height="23" HorizontalAlignment="Left" Margin="76,127,0,0" Name="button1" VerticalAlignment="Top" Width="120" />
    <TextBox Text="{Binding Path=Status}"  Height="23" HorizontalAlignment="Left" Margin="76,55,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" />
</Grid>

ViewModel.cs

    namespace bindingDemo
{
    public class ViewModel : DependencyObject , ICommand
    {
        public string Status
        {
            get { return (string)GetValue(StatusProperty); }
            set { SetValue(StatusProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Status.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StatusProperty =
            DependencyProperty.Register("Status", typeof(string), typeof(ViewModel), new UIPropertyMetadata("In Progress..."));       

        private ICommand _command = null;

        public ViewModel()
        {
            Name = "Default Name";
        }


        public void Execute(object parameter)
        {            
            Action a = new Action(() =>
            {
                ///While this code is being executed, UI gets blocked.
                Console.WriteLine(Name);
                Name = "OK";
                Status = "Connecting to database....";
                Thread.Sleep(2000);
                Status = "Connected to database....";
                Thread.Sleep(2000);
                Status = "Performing validations....";
                Thread.Sleep(2000);
                Status = "Data saved.";

            });

            /// Even if I have invoked operation asynchronously, UI is not getting updated
            /// UI is freezing for 6 seconds and can directly see last 'Status' message on UI
            Dispatcher.BeginInvoke(a, null);            
        }

        public string Name { get; set; }

        public ICommand MyCommand
        {
            get
            {
                return this;
            }
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;
    }
}

有人可以帮我解决这个问题吗?

问候, 赫曼特

最佳答案

ViewModel 通常不包含依赖属性。为了能够通过数据绑定(bind)更新 UI,它必须实现 INotifyPropertyChanged 接口(interface)。
尝试像这样实现您的 ViewModel:

public class ViewModel : INotifyPropertyChanged
{
    private string _status;

    public string Status
    {
        get { return _status; }
        set
        {
            if(_status == value)
                return;
            _status = value;

            OnPropertyChanged("Status");
        }
    }

    public event EventHandler<PropertyChangedEventArgs> PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if(handler != null)
            handler(new PropertyChangedEventArgs(propertyName));
    }

    // ...
}

在 View 模型上实现 ICommand 似乎也很奇怪。

关于c# - 使用 WPF 数据绑定(bind)设计响应式 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15918695/

相关文章:

c# - 如何在C#中获取外部IP的mac地址

c# - 使用 LINQ 计算两个字符串之间的汉明距离

multithreading - 每个核心的多个线程中存在的并行度

java - 如果任务是相关的,为什么要使用 completableFuture

c# - 将任务添加到 List<Task> 执行它们使 Task.WhenAll() 变得多余

c# - MVVM light ViewModelLocator是否有可能基于 View 动态生成 View 模型

c# - 自己订阅 PropertyChanged 或 setter 中的添加方法调用?

c# - 如何在 ScrollViewer 中滚动水平 StackPanel?

WPF - 路径/几何帮助 - 奇怪的形状

c++ - 从另一个线程杀死线程C++