在漫长的(大约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()";
答案 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之类的内容。