We have a strange issue with MVVM light. Our application has some buttons which perform tasks like starting a socketlisterner via a task:
Task.Run(() => { _serviceMonitor.SocketServer.StartListening(); });
The RelayCommands are setup to use CanExecute options:
public RelayCommand StartSocketServerCommand => _startSocketServerCommand ?? (_startSocketServerCommand = new RelayCommand(ExecuteStartSocketServerCommand, CanStartSocketServerCommand));
For unclear reasons, the UI does not always update the button state (enable/disable) correctly until we just click somewhere on the UI. Then the buttons states are correctly enabled/disabled.
Does this sounds familiar to anyone?
Related
At the moment i'm working with Caliburn Micro. But i got to a problem which i don't know how to solve.
The problem is i want to disable Buttons, but every website has only a solution with propertys. the functions of my buttons for example just start a thread to establish a connection over tcp with Netmq. So i don't know how i'll be able to disable them. Searched a lot through google but didn't find anything helpful.
Example of a button function
public void startPubButton()
{
Thread entryThread = new Thread(startPublisher);
entryThread.IsBackground = true;
entryThread.Start();
}
is there maybe a possibility to enable the Buttons only when the thread runs ?
That is the one premise behind CM wiring up by convention all you have to do is provide a CanstartPubButton Boolean property run a code check to see if you can enable or disable button according to the logic with that guard property. Call with NotifyOfPropertyChange(() => CanstartPubButton); in some fashion to do what you want. The logic with in the property (get only needed) is up to you. one other thing I will drop on you is a thread presently in the GitHub discussions on the repository itself. Might help and it might not
https://github.com/Caliburn-Micro/Caliburn.Micro/issues/422
I have a WPF application that is updating its data model within a timer which updates its data at 1 Hz. As I understand it, a Timer works on a separate thread from the GUI. Everything seems to work great, but I'm reading around and see conflicting reports on whether it's ok to update data on a thread different from the GUI thread. We are running with .NET framework 4 Client Profile. The below article says things are fixed in 4.5 but it still isn't clear to me that it is. Can someone clarify this for me? We aren't using collections in our binding as of yet. Is that why we're not having trouble.
WPF Databinding thread safety?
yeah. It is thread safe. INotifyPropertyChanged is always marshalized to UI thread from other threads.
There is no need to dispatch PropertyChanged from another thread to UI thread, as the PropertyChanged event is automatically marshalled to the UI dispatcher.
As a MSDN article says:
Note that in WPF, things are different and the code shown in Figure 5
works even if the Status property is data-bound to a TextBlock. This
is because WPF automatically dispatches the PropertyChanged event to
the main thread, unlike all the other XAML frameworks. In all other
frameworks, a dispatching solution is needed.
However, it is only true for change notifications on scalar properties (i.e. PropertyChanged event). Collection change notifications (INotifyCollectionChanged.CollectionChanged event) don't work that way, they must be raised on the UI thread manually. That is, when using INotifyCollectionChanged (such as with an ObservableCollection), these changes are not marshaled to the UI thread. This means that if you modify collection from non UI thread, you’ll take an exception. For example, there is some ViewModel We’re in the ViewModel class and we don’t use the Dispatcher to update UI. So I advise to you to use David Rickard's approach:
public static class DispatchService
{
public static void Invoke(Action action)
{
Dispatcher dispatchObject = Application.Current.Dispatcher;
if (dispatchObject == null || dispatchObject.CheckAccess())
{
action();
}
else
{
dispatchObject.Invoke(action);
}
}
}
and:
DispatchService.Invoke(() =>
{
this.MyCollection.Add("new value");
});
David Rickard article at msdn blog.
Update:
yeah, the article uses MVVMLight framework. However, it is not correct that MVVM Light uses Dispatcher to marshal scalar property to UI thread. It can be seen from source code of ViewModelBase class from MVVM Light that there is no marshal between threads to update scalar property. Please, see RaisePropertuChanged() method.
In order to dispel any doubts on dispatching scalar properties I've made a test:
XAML:
<TextBlock Text="{Binding Number}" FontSize="188" Foreground="Red" />
ViewModel:
public int Number { get; set; }
private void UpdateNumber()
{
Task.Run(() =>
{
System.Timers.Timer timer = new System.Timers.Timer(250);
timer.Elapsed += (sender, eventArgs) =>
{
Number++;
OnPropertyChanged("Number");//No exceptions, no errors
};
timer.Enabled = true;
});
}
Update 1:
There is no doubt that INotifyProperyChanged event is automatically dispatched by WPF to UI Thread. I believe a MSDN article and the link you've shown in your question:).
Pay attention to this: This is because WPF automatically dispatches the PropertyChanged event to the main thread, unlike all the other XAML frameworks.
No, it is not thread safe. A common way to fix that is by switching to the UI thread in the raiser of the notify property changed event.
Updating the view or viewmodel 1000 times per second is, in general, useless because the display is only updated 60 times per second or so and the average user is not able to read a thousand values per second in text.
The same code that raises the notification event could throttle the number of times the event gets raised per second.
I'm currently developping an application in MVVM.
I'm using for all buttons RelayCommand to perform action. The fact is that, with RelayCommand, the button is disabled when clicked on it, the time that the command is executing.
Because our rendering engine is a little bit heavy, when we open a new window, the button stay disabled for a bit, like a second.
My question is : is there a way to disable this behaviour and let the button enabled, because it changes style ?
Changing disabled style is not an option ...
I haven't see that kind of behavior on the net or in the documentation ?
Thank you
EDIT :
Two differents implementations of my RelayCommand
AnswerCommand = new RelayCommand(p => AnswerMail(p), p => IsMailSelected());
DeleteMailCommand = new RelayCommand(p => Task.Run(() => DeleteMail()), p => IsMailSelected());
I think you should synchronize the access for the block existing in the ICommand instance Execute method and every time you get there, start a new thread. If you want to click on that Button many times, having that lock section there, will put your calls in a queue. If you want to reject the requests received while it's still working you can implement the balking pattern.
https://en.wikipedia.org/wiki/Balking_pattern
This way, your button will stop being disabled when the created thread is starting.
I am not sure if this approach helps you but i think it's a feasible scenario.
One more thing, i've just found this:
Patterns for Asynchronous MVVM Applications: Commands
i haven't used it before but looks nice, i will give it a try tonight. Good luck!
I'm using the ICommand interface to perform binding on a couple of buttons in my application, the Run and Close button. I'm using a helper method that was mentioned in this question to hook up the ICommand to a delegate as follows:
_someCommand = new DelegateCommand(this.DoSomething, this.CanDoSomething);
private ICommand _someCommand;
public ICommand SomeCommand
{
get { return _someCommand; }
}
private void DoSomething(object state)
{
// do something here
}
private bool CanDoSomething(object state)
{
// return true/false here is enabled/disable button
}
This appears to work just fine as, in my implementation, CanDoSomething returns the value of a property that I have in my application.
If I set the initial value of the property to true, then the button is enabled and false it is disabled.
I have a series of events that are raised from a BackgroundWorker in the application layer back to the ViewModel that change the value of the property to true or false based on the current state of the application.
The current problem I'm having is that the button is not "re-enabling" when I set the value to true after the work has completed. If I click somewhere within the window, it will update. So, therefore, I'm thinking than manually refreshing the window will solve my problem, at least for the interim. This feels a bit gross to do it this way, but I'm kind of at a loss for what else I could try.
If anyone has any suggestions, I'm all ears.
Thanks for the help!
Ian
Edit -
A little bit more information on the application itself. It uses a background worker in the application thread to handle the "work". The application is a simple utility to manage the creating of tables and loading of data into the tables. We use a lot of pre-defined SQL scripts to setup our test environment, so this is a simple utility that allows us to do that sort of thing based on parameters provided by the user in the UI.
Hopefully that helps, because when I re-read my question it read as if I were doing everything in the UI thread, which is not the case. Progress reports are raised back up to the UI thread and everything is updated as expected, except the button..
CommandManager.InvalidateRequerySuggested() may be the answer - it tells all the commands to check whether they are enabled or not.
You have to raise the CanExecuteChanged event:
http://msdn.microsoft.com/en-us/library/system.windows.input.icommand.canexecutechanged.aspx
This may be more useful than the other answer in cases where you know you should re-evaluate a single control, and re-evaluating all the controls would be costly. The other answer is simpler if you don't have a case like that, though.
I must be retarded with searching, because here's another seemingly common problem that I haven't been able to solve.
Here's my problem -- I am using WPF and MVVM, and I have a statemachine that executes in the model. If an error occurs, I need to pass information up to the ViewModel to display the error. This part seems to work okay. When the user clicks the desired behavior, the code in the model continues, and looks at the object the user interacts with to determine what to do next.
The problem is that the model needs to reload a file, which updates the GUI with the contents of said file. Because the model is executing in a thread, you can imagine what I'm going to ask next -- how the hell do you synchronize with the GUI properly? In MFC, I would have used either SendMessage or PostMessage to accomplish the GUI update.
I've read articles for WinForms that suggest using InvokeRequired to automatically call BeginInvoke if necessary. I actually didn't know that BeginInvoke would accomplish what I wanted, so I was encouraged to learn this.
How do I actually call BeginInvoke from my model? Does this method even apply to WPF? I went ahead and implemented a delegate and then called Invoke, but I get the same error that tells me the collection can't be modified from this thread. I also tried BeginInvoke for the hell of it, but I assume that also wouldn't work because it would just launch from a different thread anyway.
Confused. If I have missed something really obvious that's been posted about all over the internet, go ahead and give me a verbal lashing, I probably deserve it.
EDIT - I should probably also add that I am looking for something other than a timer or BackgroundWorker-based solution, unless that's the only way to solve this in WPF / MVVM. Also, I wonder if any of the MVVM toolkits would have facilities for this sort of thing already...
If you want to schedule some work from a background thread to the UI thread in WPF, use the DispatcherObject. Here's a nice article on how to Build More Responsive Apps with the Dispatcher.
Update: Note that if you use an event to send notifications from the Model to the ViewModel, you still need to switch to the UI thread somewhere. Whether that switch should be in the Model or the ViewModel is a good design discussion, but it's orthogonal to your question.
The event will be raised on the corresponding Dispatcher thread. Since you need to get to the UI thread, you need to use a Dispatcher that is created on the UI thread. The easiest way to get one is to use the DispatcherObject.Dispatcher property on one of the UI elements. The alternative is to create one in your Model or ViewModel. If you are a design purist, I would suggest you create the Dispatcher in your Model and dispatch the call back to the UI thread before you raise the event to which the ViewModel is listening. This way all the thread switching and management is contained in your Model and the ViewModel works as a single-threaded on the UI thread only.
I think that your ViewModel really shouldn't know anything about the View, including whether or not it's a WPF UI, or whether or not that UI even has the concept of a Dispatcher thread, so the red flag should fly as soon as you start writing code in your ViewModel that attempts to CheckAccess() or InvokeRequired in order to marshal some code to the UI thread. Instead I'd have the model raise an event that the View can listen for and update itself accordingly, or have the ViewModel expose a property (eg. bool FileIsLoading) that the View simply binds to in order to detect and display what the model is doing asynchronously, and it's the ViewModel's responsibility to ensure that the value of that property is accurate.
For example:
public partial class MainWindow : Window {
private ViewModel _model = new ViewModel();
public MainWindow() {
InitializeComponent();
DataContext = _model;
}
private void Button_Click(object sender, RoutedEventArgs e) {
_model.Run();
}
}
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Click="Button_Click"
Content="Run"
IsEnabled="{Binding IsIdle}" />
</Grid>
</Window>
public class ViewModel : INotifyPropertyChanged {
private bool _isIdle = true;
public bool IsIdle {
get { return _isIdle; }
set {
_isIdle = value;
OnPropertyChanged("IsIdle");
}
}
public void Run() {
ThreadPool.QueueUserWorkItem((state) => {
IsIdle = false;
Thread.Sleep(10000);
IsIdle = true;
});
}
#region INotifyPropertyChanged Implementation
protected void OnPropertyChanged(string propertyName) {
PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if (propertyChanged != null) {
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
I've got another approach that seems to work, and I just wanted to throw it out there to get some comments (if anyone is even reading this question anymore!).
I started to use the MVVM Light Toolkit's Messenger class, and it seems to work really well for me. For example, let's take the ProgressBar as an example. I registered two messages with my ViewModel for setting the progress value and progress maximum. Then in my model, as it sets up the tasks and overall process, it sends these messages. When the VM receives the messages, it just updates databound values, and my GUI updates automatically! It's super duper easy, but I was wondering what you all thought about this approach. Is anyone else doing this without incident?