Bindings and updating from another thread - wpf

I just noticed what I can update binding source from another thread and it just works.
So I prepared a demo below and my questions are:
Why binding works? Why rising notification from another thread doesn't throws?
Is it legal to update source from another thread like this?
I was always using and telling to others to use Dispatcher.Invoke, but maybe I simply don't know something? Maybe binding is always guaranteed to update its target in UI thread or something like this?
<TextBox x:Name="textBox" Text="{Binding Text}" />
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Text { get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
Task.Run(() =>
{
Thread.Sleep(3000); // just wait long enough to ensure window is shown
// works
Text = "123";
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Text)));
// will crash with
// System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it'
textBox.Text = "123";
});
}
}

It's perfectly legal to set a source property on a background thread. The framework handles the marshaling for you under the hood.
If you however try to add or remove items from a source collection, it's a different story:
How to update only a property in an observable collection from thread other than dispatcher thread in WPF MVVM?
Target properties, or more exactly properties of DependencyObjects, can only be accessed on the thread on which the object was originally created though. But you don't need to use a dispatcher to set view model properties from a background thread.

Related

WPF Is there a simple way to update GUI from main thread [duplicate]

I'm a web and backend programmer by nature. Normally I try to avaoid making windows programs. Now I have to make a WPF client.
I have a background task that raises an event every often time. (It is working like a poller and when the criteria are met an event is raised). Noob as I am I wrote this code that was attached to the event to update the UI.
private void IsDisconnectedEvent()
{
UserWindow.Visibility = Visibility.Hidden;
DisconnectWindow.Visibility = Visibility.Visible;
}
This gives an exception because I am not on the same thread. After some googling I found that I should change the code with:
private void IsDisconnectedEvent()
{
Dispatcher.Invoke(() =>
{
UserWindow.Visibility = Visibility.Hidden;
DisconnectWindow.Visibility = Visibility.Visible;
});
}
This works, but this is not the only event and thus makes my code horrible ugly. Are there better ways to do this?
Regarding this:
This works, but this is not the only event and thus makes my code
horrible ugly
Yes, your WPF-based code will definitely be extremely horrible unless you understand and embrace The WPF Mentality.
Basically, all interactions between your custom logic (AKA Business logic or Application Logic) and the WPF UI should manifest in the form of Declarative DataBinding as opposed to the traditional imperative approach.
This means that there should be nothing like this:
UserWindow.Visibility = Visibility.Hidden;
anywhere in your code, simply because introducing things like that makes your code dependent on the UI and thus only executable on the UI thread.
Instead, the WPF approach to that would be to declaratively DataBind the Visibility propety of the UI element (IN XAML) to a relevant bool property that you can operate from the outside, like this:
<UserWindow Visibility="{Binding ShowUserWindow, Converter={my:BoolToVisibilityConverter}}">
<!-- ... -->
</UserWindow>
Then, you would need to create a relevant class that contains the properties the UI is expecting to bind to. This is called a ViewModel.
Notice that in order to properly support Two-Way WPF DataBinding, your ViewModels must Implement the INotifyPropertyChanged interface.
When doing so, it is also convenient to have the PropertyChanged event from that interface marshalled to the UI thread, so that you no longer have to worry about setting the ViewModel's properties by using the Dispatcher.
Therefore our first step is to have all our ViewModels inherit from a class like this:
(taken from this answer):
public class PropertyChangedBase:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
//Raise the PropertyChanged event on the UI Thread, with the relevant propertyName parameter:
Application.Current.Dispatcher.BeginInvoke((Action) (() =>
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}));
}
}
Once we have our Property Change Notification Dispatch to the UI Thread in place, we can proceed to create a relevant ViewModel that suits, in this case, the UserWindow and it's DataBinding expectations:
public class UserViewModel: PropertyChangedBase
{
private bool _showUserWindow;
public bool ShowUserWindow
{
get {return _showUserWindow; }
set
{
_showUserWindow = value;
OnPropertyChanged("ShowUserWindow"); //This is important!!!
}
}
}
Finally, you would need to set the Window's DataContext to an instance of it's corresponding ViewModel. One simple way to do that is in the Window's constructor:
public UserWindow() //Window's Constructor
{
InitializeComponent(); //this is required.
DataContext = new UserViewModel(); //here we set the DataContext
}
As you can see in this example, there is literally no need to manipulate the UI element's properties in procedural code. This is good not only because it resolves the Thread Affinity issues (because now you can set the ShowUserWindow property from any thread), but also because it makes your ViewModels and logic completely decoupled from the UI and thus testable and more scalable.
This same concept applies to EVERYTHING in WPF.
One detail that I need to mention is that I'm making use of a technique of Combining MarkupExtension and IValueConverter in order to reduce the the XAML boilerplate involved in using Converters.
You can read more about that in the link and also the MSDN DataBinding page linked above.
Let me know if you need further details.

Update WPF Window Asynchronously

I am creating a simple WPF app that when you click on a button it runs through a few steps like copy the file to a new location, convert the file then it copies the new file back to the original location.
The steps are working fine but I would like to have the WPF window update to which step it is on and hide the button while it is running.
The window only updates once it has finished running my code. I think I used to be able to do this on classic forms with me.refresh but this doesn't work on WPF.
Is something I can do to update the window after each step is complete?
Thank you
Button1.Visibility = Windows.Visibility.Hidden
FileCopy("C:\Test.xsf", AppPath & "\Convert\test.xsf")
Image7.Visibility = Windows.Visibility.Hidden
Image3.Visibility = Windows.Visibility.Visible
Program.StartInfo.FileName = xDefs
Program.StartInfo.Arguments = "/q"
Program.Start()
Program.WaitForExit()
Image5.Visibility = Windows.Visibility.Visible
FileCopy("AppPath & "\Convert\test.csv, "C:\Test.csv")
Button1.Visibility = Windows.Visibility.Visible
In order to update the UI while your program is busy, you'll need to use the Dispatcher class to add your update request onto the UI message queue. Take this synchronous example:
public void DoWorkWithFile(string filePath)
{
CopyFile(filePath);
ConvertFile(filePath);
CopyFileBack();
}
We could use the Dispatcher class to break this up and feed messages back to the UI in between tasks:
public void DoWorkWithFile(string filePath)
{
CopyFile(filePath);
RunOnUiThread((Action)delegate { SomeUiTextBlock.Text = "Copied" });
ConvertFile(filePath);
RunOnUiThread((Action)delegate { SomeUiTextBlock.Text = "Converted" });
CopyFileBack();
RunOnUiThread((Action)delegate { SomeUiTextBlock.Text = "Copied back" });
}
private object RunOnUiThread(Action method)
{
return Dispatcher.Invoke(DispatcherPriority.Normal, method);
}
I know this is a VB.NET tagged question but I'll just go ahead and share a C# solution. I hope you know enough of it to port it to VB. This is the first time and posting anything to stackoverflow, if it solves your problem please mark it as the answer :-)
You must first know a thing or two (actually a lot more) on data binding. You basically create a view model, define the property that changes with time and bind this to the window. In this case you must define a value to keep track of the current operation and let the button control.
Disclaimer, I wrote this in notepad and haven't tested it on visual studio. Be on the lookout for typos.
using System.ComponentModel;
namespace FileConverter
{
//define the various states the application will transition to
public enum OperationStatus
{
CopyingFileToNewLocation
ConvertingFile,
CopyingFileToOriginalLocation
OperationCompelete
}
//Defines the view model that shall be bound to the window.
//The view model updates the UI using event notifications. Any control that had enabled
//binding will get updated automatically
public class ViewModel : INotifyPropertyChanged//This interface defines an event used to raise an event and notify subscribers of a changed in data
{
private OperationStatus _FileConvertionStatus;
public event PropertyChangedEventHandler PropertyChanged;
public OperationStatus FileConvertionStatus
{
get
{
return _FileConvertionStatus;
}
set
{
_FileConvertionStatus=value;
//Notify all UIElements / objects that had subscribed to this property that it has changed
RaisePropertyChanged(this,"FileConvertionStatus");
}
}
public void RaisePropertyChanged(object sender,string propertyName)
{
//check if there is any object that had subscribed to changes of any of the data properties in the view model
if(PropertyChanged!=null)
PropertyChanged(sender,new PropertyChangedEventArgs(propertyName));
}
public void StartFileConvertion(string filePath)
{
//Any time we change the property 'FileConvertionStatus', an event is raised which updates the UI
this.FileConvertionStatus=OperationStatus.CopyingFileToNewLocation;
StartCopyingToNewLocation(); //call your copying logic
this.FileConvertionStatus=OperationStatus.ConvertingFile;
StartFileConvertion(); //call your conversion logic
this.FileConvertionStatus=OperationStatus.CopyingFileToOriginalLocation();
CopyFileToOriginalLocation(); //...
this.FileConvertionStatus=OperationStatus.OperationCompelete;
}
}
}
//Now for the UI section
In the constructor of the window, you must bind the window to the view model right after this window has been initialized
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ViewModel vm=new ViewModel();
//setting the data context property the window implicitly binds the whole window to our view model object
this.DataContext=vm;
string filePath="c:\file.txt";
//start the file manipulation process
vm.StartFileConvertion(filePath);
}
}
//Next step we need to bind the button to the 'FileConvertionStatus' property located in the view model. We don't bind the button to the whole view model, just the property that it's interested in. Having bound the window to the view model in the previous code, all child elements get access to the public properties of this view model (VM from now on). We do the property binding in XAML
..Button x:Name="btnStartFileProcessing" Enabled="{Binding FileConvertionStatus}"...
We're almost there. One this is missing. You'll notice that the 'Enabled' property is a Boolean value. The 'FileConvertionStatus' property is enum. Same way you can't assign an enum to a Boolean directly, you need to do some convertion. This is where converters come in.
Converters allow you to define how one property can be converted to a different one in XAML. In this case we want the button to be enabled only when file conversion is successful. Please do some reading into this.
Create a class as shown below:
using System.Windows.Data;
namespace FileConverter
{
public class OperationStatusToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType,object parameter,System.Globalization.CultureInfo culture)
{
OperationStatus status=(OperationStatus)value;
switch(status)
{
case OperationStatus.OperationCompelete:
return true; //enable the button when everything has been done
default:
return false;//disable the button as the file processing is underway
}
}
public object ConvertBack(object value, Type targetType,object parameter,System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Next step is to define the converter in XAML code. Think of this as initializing it though it can't be further from the true :-). Its more of importing the namespace into the xaml.Put the code below in the App.XAML file. Doing such declaration in the App.XAML file makes the code visible globally.
xmlns:MyConverters="clr-namespace:FileConverter"
In the Application.Resources XAML tag, declare the converter as shown below
<Application.Resources>
<MyConverters:OperationStatusToBooleanConverter x:Key="OperationStatusToBooleanConverter"/>
</Application.Resources>
Final Step
Redo the binding code in the button to include the converter.
...Button Enabled="{Binding FileConvertionStatus,Converter={StaticResource OperationStatusToBooleanConverter}}" x:Name="btnStartFileProcessing" ...
Please note that I haven't thread-optimized this code, the main problem is that all work is being done on the UI thread which can lead to the window hanging if an operation takes long.
The amount of work needed to properly set the binding up as per MVVM code standards is a lot. It might seem like an over-kill and at times, it actually is. Keep this in mind though, once the UI gets complex MVVM will definitely save the day due to the separation of concerns and binding strategies.

Order In Chaos Of Control Initialization Steps

I would like to know when is actually what happening inside initalization process of controls when I start a WPF application?
When are DP initalized? When Binding? When does DataContext get set? Is DataContext avaialbe in constructor of a control? Is there any kind of order?
I realized I ran into a trap that once I set a value on getter/setter of a DP inside constructor of a control the DP value gets updated but immediately also the values gets rolled back to default value which was null.
So my guess is that contructors get initalized first and then dependency properties.
Can somebody help me out with this?
Edit: Just for Rachel. The dp receives the value 234 and immedialty rolls back to null. I think its because constructor gets called first and then subsequently the initalizing of dps happens which sets dp back to null because null is default value. Am i thinking wrong about this? What is the order of initalization steps of a control or dependency object.
class MySuperDuperCoolClass : ContentControl
{
public MySuperDuperCoolClass()
{
InitalizeComponents();
this.MySuperDuperProperty = "234";
}
public string MySuperDuperProperty
{
get { return (string)GetValue(MySuperDuperPropertyProperty);}
set { SetValue(MySuperDuperPropertyProperty, value);}
}
public static DependencyProperty MySuperDuperPropertyProperty =
DependencyProperty.Register("MySuperDuperProperty", typeof(string), typeof(MySuperDuperCoolClass),
new PropertyMetadata(null));
}
I find the DispatcherPriority Enum useful for recalling the exact event order:
Send
Normal - Constructors run here
DataBind
Render
Loaded
Background
ContextIdle
ApplicationIdle
SystemIdle
Inactive
Invalid
Input
As you can see, Constructors get run first, followed by data bindings.
DependencyProperties get initialized when the object gets created, just like any other property, so that would occur prior to the constructor being run so the property exists in the constructor.
Setting the DataContext property or other DependencyProperties works just like any other property you are setting. If you set them with a binding, they'll get evaluated after the constructor. If you set them in the XAML, they'll get set in the Constructor. If you set them in the Loaded event, they'll get set after everything has been constructed, bound, and rendered.
You also might find this SO answer useful:
Sequence of events when a Window is created and shown
As requested, here is the sequence of major events in WPF when a
window is created and shown:
Constructors and getters/setters are called as objects are created, including PropertyChangedCallback, ValidationCallback, etc on the
objects being updated and any objects that inherit from them
As each element gets added to a visual or logical tree its Intialized event is fired, which causes Styles and Triggers to be
found applied in addition to any element-specific initialization you
may define [note: Initialized event not fired for leaves in a logical
tree if there is no PresentationSource (eg Window) at its root]
The window and all non-collapsed Visuals on it are Measured, which causes an ApplyTemplate at each Control, which causes additional
object tree construction including more constructors and
getters/setters
The window and all non-collapsed Visuals on it are Arranged
The window and its descendants (both logical and visual) receive a Loaded event
Any data bindings that failed when they were first set are retried
The window and its descendants are given an opportunity to render their content visually
Steps 1-2 are done when the Window is created, whether or not it is
shown. The other steps generally don't happen until a Window is
shown, but they can happen earlier if triggered manually.
Edit based on code added to question
Your DependencyProperty.Register method looks funny to me. The signature of the method doesn't match any of the overloads for that method, and you're using what appears to be a custom UIProperty class to set the default value instead of the normal PropertyMetadata.
I can confirm that if your code runs as expected with a normal DependencyProperty.Register signature, so the likely cause of your problem is either somewhere within your custom code, or its with how you are using/setting the property.
The code I used for a quick sample test is this:
public partial class UserControl1 : ContentControl
{
public UserControl1()
{
InitializeComponent();
this.TestDependencyProperty = "234";
}
public string TestDependencyProperty
{
get { return (string)GetValue(TestDependencyPropertyProperty); }
set { SetValue(TestDependencyPropertyProperty, value); }
}
public static DependencyProperty TestDependencyPropertyProperty =
DependencyProperty.Register("TestDependencyProperty", typeof(string), typeof(UserControl1),
new PropertyMetadata(null));
}
and the XAML is
<ContentControl x:Class="WpfApplication1.UserControl1"
x:Name="TestPanel" ...>
<Label Content="{Binding ElementName=TestPanel, Path=TestDependencyProperty}"/>
</ContentControl>
In WPF you are setting default values for DP with PropertyMetaData not via constructor.
public partial class UserControl1 : ContentControl
{
public UserControl1()
{
InitializeComponent();
}
public string TestDependencyProperty
{
get { return (string)GetValue(TestDependencyPropertyProperty); }
set { SetValue(TestDependencyPropertyProperty, value); }
}
public static DependencyProperty TestDependencyPropertyProperty =
DependencyProperty.Register("TestDependencyProperty", typeof(string), typeof(UserControl1),
new PropertyMetadata("234"));
}

Is Dispatcher not required in MVVM patern with WPF?

I am starting a new thread and trying to update UI elements through properties defined in my View Model and I am able to do it without any error, but if I try to update UI elements through code-behind, it throws the known UI access error("The calling thread cannot access this object because a different thread owns it."). First question would be ..Whats the difference between the two approaches ? Second question would be when I would use Disptacher in ViewModel ideally ?
Code Behind
private void Button_Click(object sender, RoutedEventArgs e)
{
Thread th = new Thread(new ThreadStart(delegate()
{
textbox.Text = "Rajib";
}
));
th.Start();
}
//inside XAML
<TextBox x:Name="textbox" Text="{Binding UserInput, Mode=TwoWay}" />
MVVM
public string UserInput
{
get { return _UserInput; }
set { _UserInput = value; OnPropertyChanged("UserInput"); }
}
//Called through a ICommand property on a button click
public void ExecuteCommand(object obj)
{
InvokeCallThroughAnonymousDelegateThread();
}
private void InvokeCallThroughAnonymousDelegateThread()
{
ThreadStart start = delegate()
{
UserInput = "Calling from diff thread";
};
new Thread(start).Start();
}
Any attempt to update the UI must be done within the dispatcher thread. However, for property change events, WPF automatically dispatches for you when the event is raised from a background thread. You can read more about this on Bea Costa's (former WPF data binding PM) blog:
http://bea.stollnitz.com/blog/?p=34
They were going to do the same for INotifyCollectionChanged events but never got around to it in prior releases. For 4.5 they will now be synchronizing collection changed events automatically in addition to INotifyPropertyChanged.
The NotifyPropertyChanged has its thread context changed by WPF through the event, but your code behind doesn't change the thread context to the UI Thread. In your codebehind, use this instead:
Task.Factory.StartNew(() =>
{
// Background work
}).ContinueWith((t) => {
// Update UI thread
}, TaskScheduler.FromCurrentSynchronizationContext());
Regarding when to use the Dispatcher directly, I have a mid-sized project where I haven't used the Dispatcher in any ViewModel. I have used it to deal with Xaml resources, weak event handling, and it is used inside of MefedMVVM and Prism, which I also use.

wpf: update multiple controls via dispatcher

I'm reading data from a serial port using an event listener from the SerialPort class. In my event handler, I need to update many (30-40) controls in my window with xml data coming over the serial port.
I know that I must use myControl.Dispatcher.Invoke() to update it since it's on a different thread, but is there a way to update lots of controls together, rather than doing a separate Invoke call for each (i.e. myCon1.Dispatcher.Invoke(), myCon2.Dispatcher.Invoke(), etc)?
I'm looking for something like calling Invoke on the container, and updating each child control individually, but I can't seem to work out how to accomplish this.
Thanks!
What you need to do is use MVVM.
You bind your controls to public properties on a ViewModel. Your VM can listen to the serial port, parse out the xml data, update its public properties, and then use INotifyPropertyChanged to tell the UI to update its bindings.
I'd suggest this route as you can batch notifications and, if you have to, use the Dispatcher to invoke the event on the UI thread.
UI:
<Window ...>
<Window.DataContext>
<me:SerialWindowViewModel />
</Window.DataContext>
<Grid>
<TextBlock Text="{Binding LatestXml}/>
</Grid>
</Window>
SerialWindowViewModel:
public class SerialWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string LatestXml {get;set;}
private SerialWatcher _serialWatcher;
public SerialWindowViewModel()
{
_serialWatcher = new SerialWatcher();
_serialWatcher.Incoming += IncomingData;
}
private void IncomingData(object sender, DataEventArgs args)
{
LatestXml = args.Data;
OnPropertyChanged(new PropertyChangedEventArgs("LatestXml"));
}
OnPropertyChanged(PropertyChangedEventArgs args)
{
// tired of writing code; make this threadsafe and
// ensure it fires on the UI thread or that it doesn't matter
PropertyChanged(this, args);
}
}
And, if that isn't acceptable to you (and you want to program WPF like its a winforms app) you can use Dispatcher.CurrentDispatcher to Invoke once while you manually update all controls on your form. But that method stinks.

Resources