Are "volatile" data bindings in Windows Forms possible? - winforms

Let's assume I'm implementing a Winforms UI where all commands adhere to the following pattern:
interface ICommand
{
bool CanExecute { get; }
void Execute();
}
Buttons or menu items that trigger such a command should have the following set-up:
property Enabled is bound to the command's CanExecute
event Click is linked to the command's Execute (through an intermediate event handler due to the differing method signatures)
The trouble with CanExecute is, implementing INotifyPropertyChanged for it won't work here, as this property cannot be directly modified, but depends on other factors in the program which needn't be related to the command. And one shouldn't have to trigger the command's PropertyChanged event in completely unrelated parts of the program.
How do you let the data binding manager know when CanExecute has changed?
Here's a (purly fictional) example of my problem:
bool CanExecute
{
get
{
return User.LoggedInForAtLeastNMinutes(5);
// how would you trigger data-binding updates for CanExecute?
}
}
Ideally, I'd like to have the UI constantly checking CanExecute (as if it were a volatile field), but AFAIK this is not how Winforms data binding works. Does anyone have a solution for this problem?
Note: I am aware of WPF, btw. The background of my question is that I'm going to gradually improve an existing Winforms application in the general direction of WPF. But actually using WPF and thus getting rid of the problem I've asked about is not feasible right now.

I would implement INotifyPropertyChanged regardless (or add a CanExecuteChanged event, which has the same effect). I would try hard for objects to know when to raise the property changed event at the right time, rather than polling.
For instance, in your fictional example, you could have a UserLoggedIn event. In response to that, you could set a 5-minute timer; when that timer elapses, you raise the property changed event.
If you go for the polling approach then you face two dangers:
Polling too often, where your application consumes CPU checking for events that can't possibly happen yet (for instance, polling every 10 seconds to see if 5 minutes are up)
Not polling often enough, where controls bound to CanExecute properties lag the rest of the UI (for instance, a delay between making a text selection and the CopyTextCommand.CanExecute property updating)
A hybrid approach is that taken by Microsoft Foundation Classes in C++, which was to make this check any time the application's message loop was idle. This is a reasonable approach when you know that only user interface interaction that can affect your CanExecute property.

Use a Timer to constantly poll the CanExecute property. Raise the PropertyChanged event when the property changes.

I' do the polling on the Application.Idle event, as long as your can execute logic is simple, there shouldn't be any problem.
here is an extract of my current 'CommandManager' implementation;
public CommandManager()
{
Commands = new List<ICommand>();
Binders = new List<ICommandBinder>
{
new ControlBinder(),
new MenuItemCommandBinder()
};
Application.Idle += UpdateCommandState;
}
private void UpdateCommandState(object sender, EventArgs e)
{
Commands.Do(c => c.Enabled);
}
(Do() is just an extension method that does a foreach, like linq Select() but taking Action instead of Func)
I've blogged about this some time ago, feel free to check: http://codewithpassion.blogspot.com/2010/11/icommand-and-commandmanager-for-windows.html
hope it helps

Related

In what scenarios might ICommand CanExecute not update?

I've been using Josh Smith's implementation of RelayCommand in a couple of large projects for some years now. However today I've come across a scenario where the CanExecute on one of my commands isn't refreshing. I'm at a loss as to what's causing it - the view-model isn't doing anything that I haven't done dozens of times already.
The VM's constructor creates a couple of commands. The first one is a "start" command:-
StartCommand = new RelayCommand(o => StartAsync(), o => true);
The StartAsync() method looks like this:-
private async void StartAsync()
{
IsRunning = true;
await Task.Run(() => SomeLongRunningProcess(); }
IsRunning = false;
}
There is also a "save" command:-
SaveCommand = new RelayCommand(o => Save(), o => !IsRunning);
('IsRunning' is a bog-standard property, implementing INotifyPropertyChanged. As well as being used for the "CanExecute" delegate, it's also bound to the IsEnabled property of a few controls in the view to enable/disable them).
When I click my "Start" button (bound to 'StartCommand'), the "Save" button is correctly disabled. The b/g process runs to completion, then IsRunning is set to false, but this doesn't trigger the "Save" button to become enabled. It only enables if I click somewhere on my view.
(The controls whose IsEnabled property is bound to the VM IsRunning property do enable and disable correctly, by the way).
I've come across a few SO articles about this, but nothing really explains why this happens. My workaround was to bind the button's IsEnabled property to 'IsRunning', but it's frustrating that this particular view refused to play ball. Any thoughts on what might be causing this? Common sense says it's something specific to this view/VM, but I'm stumped (and I'm not going to post the code here - there's too much of it).
Yes, because the version of RelayCommand you're using is depending on CommandManager.RequerySuggested event and it's not accurate.
Its documentation states that
Occurs when the CommandManager detects conditions that might change
the ability of a command to execute.
Basically it guesses all the possible events where your data could be changed. It can never know when your ViewModel/Model is changed. It isn't listening for the property change notifications.
If you want to react immediately without waiting for CommandManager to guess, you need to fire the ICommand.CanExecuteChanged manually yourself when model is updated.
You saw that the event not fired unless you click the window or something but do note that it could fire several times too

Silverlight Binding to commands

Sometimes when I bind to commands to a ViewModel, my CanExecute code does not always get called and hence my buttons are not disabled when they should be.
Any ideas?
Thanks
When canExecute is not called the first time, that's a binding problem.
If it's not 'automatically' called second,[n]th time, that's the normal behavior.
Imagine, how the UI should know that it should requery your predicate? When you have a command parameter it will call your predicate every time the parameter changes. Generally, some UI 'events' also requery it (focus, updatelayout etc), but not always (that's good, it would be pointless to reevaluate every command binding all time). So you cannot rely on it. You make the business logic, so you know when it needs an update, not the UI. The UI 'cannot see inside your predicate delegate' and watch what happens. You have to notify the UI about it, same as you notify when a property changed.
ICommand has an event, so you must implement it, it's the CanExecuteChanged.
You should implement a public method to fire it (or it is already implemented if you use a framework, like MVVMLight or Prism).
A simple implementation.
public void RaiseCanExecuteChanged()
{
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
So you can call it on your command whenever your canExecute state changes in your business logic and it is going to notify all the subscribers, which is your button in this case.
You mention the state of the button not being disabled. This seems more like a binding issue than binding to commands. Is the state of the property you are binding to changing? When is it changing, etc.?

WPF MVVM application - ICollectionView/Threading/General Questions

I have a few questions regarding to building WPF MVVM applications.
1) I'm using ICollectionView objects for databound controls such as ListView and ComboBox. I found this was the simplest way of gaining access to/tracking the selected item of these controls. What is the best way to replace the contents of ICollectionView? Currently I'm doing it like so:
private ICollectionView _files;
public ICollectionView Files {
get { return _files; }
}
void _service_GetFilesCompleted(IList<SomeFile> files) {
this.IsProcessing = false;
_files = CollectionViewSource.GetDefaultView(files);
_files.CurrentChanged += new EventHandler(FileSelectionChanged);
OnPropertyChanged("Files");
}
I didn't know whether it was necessary to reattach the handler every time I refresh the list of files?
2) Now that I've got my head round it, I am starting to like the MVVM pattern. However, one concept I'm not completely sure about is how to send notifications back down to the view. Currently I am doing this by binding to properties on my ViewModel. For example, in the above code I have an "IsProcessing" property that I use to determine whether to display a ProgressBar. Is this the recommended approach?
3) Following on from 2) - there doesn't seem to be a standard way to handle exceptions in an MVVM application. One thought I had was to have one method on my ViewModel base class that handled exceptions. I could then inject an IMessagingService that was responsible for relaying any error messages. A concrete implementation of this could use MessageBox.
4) I have a few tasks that I want to perform asynchronously. Rather than adding this logic directly in my service I created a decorator service that runs the underlying service methods on a new thread. It exposes a number of events that my ViewModel can then subscribe to. I have listed the code below. I understand that BackgroundWorker is a safer option but did not know whether it was suitable for running multiple asynchronous tasks at once?:
public void BeginGetFiles()
{
ThreadStart thread = () => {
var result = _serviceClient.GetUserFiles(username, password);
GetFilesCompleted(result.Files);
};
new Thread(thread).Start();
}
Finally, I realize that there are a number of MVVM frameworks projects that handle some of these requirements. However, I want to understand how to achieve the above using built-in functionality.
Thanks
If you have ListViews and ComboBoxes, you should really be considering an ObservableCollection<> to bind to these controls. Adding and removing items from the collection will automatically notify the control the property has changed.
If you're doing background processing, you can look at the BackgroundWorker or DispatcherTimer to handle updates to the UI. These both have the capability of acting on the UI thread, and can be thread safe.
To get the selected item from a combo box, expose an INotifyCollectionChanged object such as ObservableCollection and bind it to the itemsource, then create another property for the current item and binding ComboBox.SelectedItem (or ComboBox.SelectedValue if required) to it. You will need to manage the selection when updating the collection.
On the face of it, ICollectionView seems like the obvious choice but the WPF implementation really forces your hand on some threading code that you really shouldn't be troubled with.
I used ICollectionView and CollectionViewSource recently (for filtering) and have become frustrated with how many dispatcher issues have crept in. Today I am probably going to revert to the method i describe above.

WPF DataGrid calls BeginEdit on an IEditableObject two times?

I've got a DataGrid bound to a collection of IEditableObject's.
Now when I click two times in a cell, it will be opened for editing.
Funny thing is: BeginEdit will be called two times. Sometimes for the same EditableObject, but sometimes for two different objects (especially when I use PgDn until I hit the end of the DataGrid) the correct one will be called first, then some other item from the collection, which never had been in focus before.
EndEdit is called twice, too, but always for the selected Item, not for the wrong one.
Is this a known problem? Any workarounds to get only (the right) one notification.
If you look at the stack trace in the debugger when BeginEdit is called, you'll see that the first time, it's the collection view calling it, and the second time, it's a BindingGroup.
The problem appears to be that there are two things that both think they are in charge of the IEditableObject state. When WPF provides a default collection view, it will look for IEditableObject on the objects in the collection, and will call BeginEdit and either EndEdit or CancelEdit in response to calls to the corresponding IEditableCollectionView methods. But also, the BindingGroup will call the IEditableObject methods in response to calls to BeginEdit and CommitEdit or CancelEdit.
The DataGrid uses both features: when you start and complete edits in a row, it notifies the IEditableCollectionView and the BindingGroup and both of those things think that it's their responsibility in turn to go on and notify the IEditableObject implementation on the underlying source object.
So it looks rather like a bug in the DataGrid - it causes two different objects to call BeginEdit (and related methods). And it's because it makes use of editable collection views and binding groups - from the look of it, those weren't designed to be used at the same time on the same objects, in the way that the DataGrid uses them.
The reason you don't see this problem with the grid in the Toolkit is that it appears to be a slightly older version - comparing the code in that with what Reflector shows for .NET 4.0, you'll see that the .NET 4.0 DataGrid has some extra code (a new method, EnsureItemBindingGroup, and some related code in MeasureOverride and OnRowValidationRulesChanged) that ensures that a binding group always exists, whether you ask for it or not. So if the WPF Toolkit is updated, it'll probably grow a similar feature unless this gets fixed. (And I would guess that if you use the current edition - February 2010 as I write this - of the WPF Toolkit, and you use the ItemBindingGroup property to ask explicitly for a binding group, you'd see exactly the same problem.)
This doesn't explain how you'd get calls to BeginEdit on random objects as you've described. I can't repro that. But it does explain double calls on the selected object. The best thing to do appears to be to code your source objects so that they will tolerate the double calls.
I'm not sure what you'd use to interrupt the BeginEdit event before it happens, but for EndEdit a simple isDirty marker will do. In your Entity class that implements IEditableObject, add the following:
private bool _isDirty = false;
#region IEditableObject Members
public void BeginEdit()
{
// Bug Fix: Windows Controls call EndEdit twice; Once
// from IEditableCollectionView, and once from BindingGroup.
// This makes sure it only happens once after a BeginEdit.
_isDirty = true;
}
public void CancelEdit() { }
public void EndEdit()
{
if (ItemEndEdit != null && _isDirty)
{
_isDirty = false;
ItemEndEdit(this);
}
}
#endregion
I have same problem using .NET Framework 4 DataGrid.
Add Reference to last version of WPFToolkit
Add
xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
and change <DataGrid> with <dg:DataGrid>
+1 #IanGriffiths for diagonsing the Problem. As for a solution (or workaround rather), you can count the number of "pending" Edits. That means something like:
void BeginEdit()
{
_numEdits++;
}
void CancelEdit()
{
if(--_numEdits < 0)
throw new Exception("WTF?");
}
void EndEdit()
{
CancelEdit();
if(_numEdits == 0)
commitEdit();
}

WPF: how to signal an event from ViewModel to View without code in codebehind? [duplicate]

This question already has answers here:
How can I Have a WPF EventTrigger on a View trigger when the underlying Viewmodel dictates it should?
(4 answers)
Closed 8 years ago.
I have quite simple (I hope :)) problem:
In MVVM, View usually listens on changes of ViewModel's properties. However, I would sometimes like to listen on event, so that, for example, View could start animation, or close window, when VM signals.
Doing it via bool property with NotifyPropertyChanged (and starting animation only when it changes from false to true) is possible, but it feels like a hack, I'd much prefer to expose event, as it is semantically correct.
Also, I'd like to do it without code in codebehind, as doing viewModel.myEvent += handler there would mean that I'd have manually unregister the event in order to allow View to be GC'd - WPF Views are already able to listen on properties 'weakly', and I'd much prefer to program only declaratively in View.
The standard strong event subscription is also bad, because I need to switch multiple ViewModels for one View (because creating View every time takes too much CPU time).
Thank you for ideas (if there is a standard solution, a link to msdn will suffice)!
Some comments:
You can use the weak event pattern to ensure that the view can be GC'd even if it is still attached to the view model's event
If you're already switching multiple VMs in for the one view, wouldn't that be the ideal place to attach/detach the handler?
Depending on your exact scenario, you could just have the VM expose a state property which the view uses as a trigger for animations, transitions, and other visual changes. Visual state manager is great for this kind of thing.
This is something that I wrestled with as well...
Similar to what others are saying, but here is an example with some code snippets... This example shows how to use pub/sub to have a View subscribe to an event fired by the VM - in this case I do a GridView. Rebind to ensure the gv is in sync with the VM...
View (Sub):
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Presentation.Events;
private SubscriptionToken getRequiresRebindToken = null;
private void SubscribeToRequiresRebindEvents()
{
this.getRequiresRebindToken =
EventBus.Current.GetEvent<RequiresRebindEvent>()
.Subscribe(this.OnRequiresRebindEventReceived,
ThreadOption.PublisherThread, false,
MemoryLeakHelper.DummyPredicate);
}
public void OnRequiresRebindEventReceived(RequiresRebindEventPayload payload)
{
if (payload != null)
{
if (payload.RequiresRebind)
{
using (this.gridView.DeferRefresh())
{
this.gridView.Rebind();
}
}
}
}
private void UnsubscribeFromRequiresRebindEvents()
{
if (this.getRequiresRebindToken != null)
{
EventBus.Current.GetEvent<RequiresRebindEvent>()
.Unsubscribe(this.getRequiresRebindToken);
this.getRequiresRebindToken = null;
}
}
Call unsub from the close method to prevent memory leaks.
ViewModel (Pub):
private void PublishRequiresRebindEvent()
{
var payload = new RequiresRebindEventPayload();
payload.SetRequiresRebind();
EventBus.Current.GetEvent<RequiresRebindEvent>().Publish(payload);
}
Payload class
using System;
using Microsoft.Practices.Composite.Presentation.Events;
public class RequiresRebindEvent
: CompositePresentationEvent<RequiresRebindEventPayload>
{
}
public class RequiresRebindEventPayload
{
public RequiresRebindEventPayload()
{
this.RequiresRebind = false;
}
public bool RequiresRebind { get; private set; }
public void SetRequiresRebind()
{
this.RequiresRebind = true;
}
}
Note that you can also set the constructor up to pass in a Guid, or some identified in, which can be set on Pub and checked on sub to be sure pub/sub is in sync.
imho yYand separated
state - to be able to move data back/forth between view <-> vm
actions - to be able to call onto view model functions/commands
notifications - to be able to signal to the view that something has happened and you want it to take a viewy action like make an element glow, switch styles, change layout, focus another element etc.
while is true that you can do this with a property binding, its more of a hack as tomas mentioned; always has felt like this to me.
my solution to be able to listen for 'events' from a view model aka notifications is to simple listen for data-context changes and when it does change i verify the type is the vm i'm looking for and connect the events. crude but simple.
what i would really like is a simple way to define some 'view model event' triggers and then provide some kind of handler for it that would react on the view side of things all in the xaml and only drop to code behind for stuff thats not do-able in xaml
Like adrianm said, when you trigger your animation off a bool property you are actually responding to an event. Specifically the event PropertyChanged which the WPF subsystem. Which is designed to attach/detach correctly to/from so that you don't leak memory (you may forget to do this when wiring an event yourself and cause a memory leak by having a reference active to an object which otherwise should be GCed).
This allows you to expose your ViewModel as the DataContext for the control and respond correctly to the changing of properties on the datacontext through databinding.
MVVM is a pattern that works particularly well with WPF because of all these things that WPF gives you, and triggering off a property change is actually an elegant way to use the entire WPF subsystem to accomplish your goals :)
A more general question to ask is: "Why am I trying to deal with this event in my ViewModel?"
If the answer has anything to do with view-only things like animations, I'd argue the ViewModel needs not know about it: code behind (when appropriate), Data/Event/PropertyTriggers, and the newer VisualStateManager constructs will serve you much better, and maintain the clean separation between View and ViewModel.
If something needs to "happen" as a result of the event, then what you really want to use is a Command pattern - either by using the CommandManger, handling the event in code behind and invoking the command on the view model, or by using attached behaviors in the System.Interactivity libs.
Either way, you want to keep your ViewModel as "pure" as you can - if you see anything View-specific in there, you're probably doing it wrong. :)

Resources