Reputation: 5232
During a lengthy (about 1 minute) process I am trying to log some progress by writing time-stamped messages to a text control. But all messages appear at once. Apparently, all PropertyChanged events
are queued until my busy process is done, and received by the text control all at once. How can I kind of 'flush' the events in the middle of my busy process? I searched but could not find a Flush/Update/Dispatch call to immediately process queued events.
A multi threaded solution is in question 1194620, but I would first like to avoid multithreading if possible. In older environments (C++, .Net Winforms/ASP) there were always system calls like Update
to interrupt a busy process to handle pending events.
Edit: Please don't tell me that that a lengthy process should be in another thread. I agree. But this is inherited code, and before I would even think about converting to multithreaded, I first need to log certain events to understand what it does. Besides, this app has many other problems that need to be fixed first. Also, after fixing problems, the lengthy process might not be lenghty anymore.
The method of writing strings from anywhere in de code I found in question 18888937 and works fine.
This is the code-behind. Edit: I added the call to the solution in the Accepted Answer.
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
}
}
this is the text control:
<TextBlock x:Name="textblock_StartupMessages"
Margin="10" TextWrapping="Wrap"
Text="{Binding Path=StartupMessage, Source={x:Static Application.Current}}">
</TextBlock>
and here is how I place messages from another place in the code:
public class AllRoutesViewModel : ViewModelBase
{
public AllRoutesViewModel()
{
(System.Windows.Application.Current as App).StartupMessage =
"start of AllRoutesViewModel()";
Upvotes: 2
Views: 333
Reputation: 3897
You might consider using Dispatcher.PushFrame.
More information is available about the class here.
Also, here is the relevant code sample from MDSN (slightly modified):
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;
}
While this solution might give you want you want in this case, I have to agree with what others have said about design patterns. Please consider something like MVVM in the future.
Upvotes: 1
Reputation: 31721
avoid multithreading if possible. In older environments (C++, .Net Winforms/ASP) there were always system calls like Update to interrupt a busy process to handle pending events.
This is attempting a design pattern on a system which was designed not to behave like the systems you mentioned.
Long running operations should not be done on the GUI thread in WPF.
Notify property change only works when the GUI thread is not blocked because it is inherently a GUI process. The code you have is blocking the GUI thread. If you properly run the task in a background worker, or an async task and properly update your property, the notify will make the GUI behave visually as you actually want and expect.
But by the design you present, to graphically do this is impossible. The best answer is to learn the WPF design pattern and follow it, instead of forcing a different technologies design pattern.
Upvotes: 4