【问题标题】:WPF UI Update with INotifyPropertyChanged使用 INotifyPropertyChanged 更新 WPF UI
【发布时间】:2013-11-18 21:09:58
【问题描述】:

感谢您的宝贵时间。我对 WPF 有这样的问题......它更新 UI,它仅在方法(由按钮单击触发)到达其结束时更新它。但是,在我的真实应用中,我需要立即更新 UI 以查看信息。

我尝试阅读教程和帖子,但我已经准备好放弃了....我将不胜感激任何想法为什么会发生以及该怎么做:-)。

我有一个标准的 xaml:带有一个文本框和一个按钮:

<TextBox Text="{Binding FirstName}"/>
<Button Content="Run" Click="Button_Click" />

背后

 public partial class MainWindow
    {
        public Person Person = new Person();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = Person;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Person.FirstName = "John";
            Thread.Sleep(10000);
///// Only Here I can see the update.
        }
    }

而DataContext是:

    public class Person:INotifyPropertyChanged
    {
       private string _FirstName;

        public string FirstName
        {
            get { return _FirstName; }
            set
            {
                if (_FirstName == value)
                    return;
                _FirstName = value;
                OnPropertyChanged("FirstName");

            }
        }
....

标准 OnProertyChanged 实现。

【问题讨论】:

  • 删除Thread.Sleep()。您正在使 UI 线程休眠,因此它无法重新渲染。
  • 嗨,HighCore,感谢您的回答。但这只是对我真实应用程序工作流程的模拟。在真正的应用程序中,我有一个 Selenium webdriver 测试,我想通知用户这些测试。谢谢

标签: c# wpf inotifypropertychanged


【解决方案1】:

您永远不应该使用Sleep 阻塞 UI 线程。相反,您可能希望将这部分代码放在后台线程上。例如,使用 Task.Factory.StartNew:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Person.FirstName = "John";
    Task.Factory.StartNew( () => {
        Thread.Sleep(10000);

        // ...
    });
}

请注意,您不能在该线程内进行任何其他 UI 更改。如果需要,请使用 Dispatcher.BeginInvoke 将它们发送回 UI 线程。

例如,根据评论:

Person.FirstName = "John";
Task.Factory.StartNew( () => {
    foreach (string mlsNumber in ourMlses) 
    { 
        Listing listing = sourceSite.ParseByMls(mlsNumber); 
        if (listing != null) 
        { 
            var successDb = sourceSite.UpdateListing(listing); 
            if (!successDb) 
            { 
                throw new Exception("Db error"); 
            } 

            Dispatcher.BeginInvoke( () => {

                // UI update that listing have been added to the DB 
            });
        }
    }
} );

【讨论】:

  • 您好 McGarnagle,非常感谢您的回复。抱歉,这可能不是最聪明的问题,foreach (string mlsNumber in ourMlses) { Listing Listing = sourceSite.ParseByMls(mlsNumber); if (listing != null) { var successDb = sourceSite.UpdateListing(listing); if (!successDb) { throw new Exception("Db error"); } // UI 更新该列表已添加到数据库中
  • @Svitlana 我已经在上面更新了......想法是将数据库/耗时的任务放到后台线程中,然后将任何与 UI 相关的内容分派回 UI 线程。跨度>
【解决方案2】:

我假设您正在 Button_Click 方法中运行一个冗长的操作,并希望首先使用新的 FirstName 更新 UI。尝试在 Dispatcher.Invoke 方法中结束您的 FirstName 初始化:

 private void Button_Click(object sender, RoutedEventArgs e)
 {
      Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, 
            new Action(() => {
                Person.FirstName = "John";
            }));
      // Run a lengthy operation here
 }

它会以与退出 Button_Click 方法后相同的方式触发 PropertyChanged 事件的 UI 更新。

P.S. 但是,您在这里看到的所有代码都是非常糟糕的做法,我会谋杀编写它的开发人员。但它可能适合一些学术目的。要做出正确的解决方案,最好使用Commands 并在ViewModel 中处理它,而不是点击处理程序。

【讨论】:

  • 最后一个问题。我可以提高您和其他回复者的声誉吗?
  • 不用担心。做两件事:1)将最佳回复标记为您问题的答案; 2) 为您最喜欢的回复点赞(可以是新手点赞之间的时间限制)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-12
  • 2014-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-30
相关资源
最近更新 更多