如何在繁忙的过程中快速处理事件,是否有更新命令?

时间:2014-09-05 14:07:20

标签: c# wpf .net-4.0 inotifypropertychanged

在漫长的(大约1分钟)过程中,我试图通过将时间戳消息写入文本控件来记录一些进度。但所有消息都会立即出现。显然,所有PropertyChanged events都排队,直到我的忙碌过程完成,并由文本控件同时收到。我怎样才能在繁忙的过程中“冲洗”事件?我搜索但找不到Flush / Update / Dispatch调用来立即处理排队事件。

多线程解决方案在question 1194620,但我首先想尽可能避免多线程。在较旧的环境(C ++ ,. Net Winforms / ASP)中,总是有像Update这样的系统调用来中断繁忙的进程以处理挂起的事件。

编辑:请不要告诉我,冗长的进程应该在另一个线程中。我同意。但这是继承的代码,在我考虑转换为多线程之前,我首先需要记录某些事件以了解它的作用。此外,这个应用程序还有许多其他问题需要先修复。此外,在解决问题后,漫长的过程可能不再是长篇大论。

我在question 18888937中找到的代码中的任意位置编写字符串的方法,并且工作正常。

这是代码隐藏。 编辑:我在接受的答案中添加了对解决方案的调用。

public partial class App : Application, INotifyPropertyChanged
{
    /// <summary>
    /// Property for the log message for the TextBlock control
    /// </summary>
    public string StartupMessage
    {
        get { return _StartupMessage; }
        set
        {
            if (_StartupMessage.Length == 0)
            {
                _StartupMessage = string.Format("{0:HH-mm-ss} {1}", 
                                          DateTime.Now, value);
            }
            else
            {
                _StartupMessage = string.Format("{0}{1}{2:HH-mm-ss} {3}",
                  _StartupMessage, Environment.NewLine, DateTime.Now, value);
            }
            OnPropertyChanged("StartupMessage");
        }
    }
    private string _StartupMessage = "";

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
            DoEvents();//see the accepted answer below
        }
    }

这是文本控件:

<TextBlock x:Name="textblock_StartupMessages" 
             Margin="10" TextWrapping="Wrap" 
  Text="{Binding Path=StartupMessage, Source={x:Static Application.Current}}">
</TextBlock>

以下是我如何从代码中的其他位置发送消息:

public class AllRoutesViewModel : ViewModelBase
{
    public AllRoutesViewModel()
    {
        (System.Windows.Application.Current as App).StartupMessage = 
                                           "start of AllRoutesViewModel()";

2 个答案:

答案 0 :(得分:4)

  

尽可能避免多线程。在旧环境中(C ++,。Net   Winforms / ASP)总是有系统调用,如Update to interrupt   处理待处理事件的繁忙过程。

这是在一个设计 not 的系统上尝试一种设计模式,就像你提到的系统一样。

不应在WPF中的GUI线程上执行长时间运行的操作。

通知属性更改仅在GUI线程未被阻止时才起作用,因为它本身就是一个GUI进程。您拥有的代码是阻止GUI线程。如果正确在后台工作程序中执行任务,或者异步任务并且正确更新您的属性,则通知将使GUI按照您的实际需要和期望进行操作。

但是根据您提出的设计,以图形方式这样做是不可能的。最好的答案是学习WPF设计模式并遵循它,而不是强制不同的技术设计模式。

答案 1 :(得分:1)

您可以考虑使用Dispatcher.PushFrame

有关课程here的更多信息。

此外,这里是来自MDSN的相关代码示例(略有修改):

using System.Windows.Threading;  //DispatcherFrame, needs ref to WindowsBase

//[SecurityPermissionAttribute(SecurityAction.Demand, Flags =   SecurityPermissionFlag.UnmanagedCode)]
public void DoEvents()
{
    DispatcherFrame frame = new DispatcherFrame();
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
        new DispatcherOperationCallback(ExitFrame), frame);
    Dispatcher.PushFrame(frame);
}

public object ExitFrame(object f)
{
    ((DispatcherFrame)f).Continue = false;

    return null;
}

虽然这个解决方案在这种情况下可能会让你想要,但我必须同意其他人对设计模式的看法。请在将来考虑MVVM之类的内容。