Business Oriented Software Solutions or : "How to best compose processes & technologies to deliver fast time to market, feature and user oriented, high quality software solutions"
A common pattern for developping applications with SilverLight and WPF is the Model-View-ViewModel (MVVM) Design Pattern. The MVVP pattern is an evolution of the MVC and MVP well-known pattern, specially adapted to the advanced data binding features of WPF and SilverLight. Please refer to the following excellent MSDN article from Josh Smith for a complete description and implementation of the MVVM Pattern for WPF:
However, as stated in this article title, we're talking about an MVVM pattern for WPF. For those who have tried to develop portable applications working on both WPF and SilverLight, you know this frustration of discovering small differences between WPF and SilverLight and missing classes in SilverLight as compared to WPF.
And in our specific case, Josh defines a RelayCommand class, used to simplified the binding with user interface elements commands with underlying actions in the ViewModel class.
Here is the definition of the RelayCommand class:
public class RelayCommand : ICommand
{
#region Fields
readonly Action
This class makes use of the CommandManager object and the RequerySuggested event. When a user actions the UI in WPF, this triggers the CommandManager to requery all the commands. In Silverlight the CommandManager class does not exist: you have to do the work yourself!
So I created the following RelayCommand implementation, working for SilverLight:
public class RelayCommand : ICommand
{
#region Fields
readonly Action _execute;
readonly Predicate _canExecute;
///
/// In WPF we could use CommandManager. Does not work with SilverLight. Using this ICommandManager interface provides an alternative working for both SilverLight and WPF
///
readonly ICommandManager _commandManager;
#endregion // Fields
#region Constructors
///
/// Creates a new command that can always execute.
///
/// The execution logic.
public RelayCommand(Action execute, ICommandManager commandManager)
: this(execute, null, commandManager)
{
}
///
/// Creates a new command.
///
/// The execution logic.
/// The execution status logic.
public RelayCommand(Action execute, Predicate canExecute, ICommandManager commandManager)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
_commandManager = commandManager;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { _commandManager.RequerySuggested += value; }
remove { _commandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
}
And here is the definition of the ICommandManager interface:
public interface ICommandManager
{
event EventHandler RequerySuggested;
}
Now when creating a new command, you should pass a reference to an object implementing the ICommandManager interface. This object will usually be the ViewModel class itself. It is then the responsability of the ViewModel class to trigger the RequerySuggested event when anything in the state of the ViewModel changed that requires the command to be rebinded.
That's it, this completes the SilverLight implementation of the MVVM pattern.
WPF is great! I love it. Just so much more convenient and relevant to building user interfaces than Windows Forms!
However, unless you're using third parties components like Telerik, there is still a lack of controls. I recently had the need for a Split button: I button that shows a menu when clicked, to enable kind of a "multi-choices" button.
Here I found a nice and neat implementation of such a control:
I have been struggling sometime now trying to handle the following scenario, which seems quite simple at first. This problem highlights the difficulties one can face when doing WPF and/or SilverLight developments: while the most cases are working just fine and great, you will regularly face issues you were not expecting. Making WPF/SilverLight development rather complex.
The scenario is the following: I have a page, composed of several controls. The composing controls are themselves composite controls : there are composed of multiple UI controls
I want to style my page the following way: whenever the user moves his mouse cursor over a control, I want to play an animation to highlight this control. And whenever the user moves his mouse cursor out of a control, I want to play an animation to remove highlight on this control
Let illustrate this with a concrete example: I have a page showing a grid view of products and a form view displaying the details of the selected product. The grid view and the form view are two composite user controls composed of other controls.
Whenever the grid view is focused, I want the following visual result:
And whenever the form view is focused, I want the following visual result:
Well... seems quite obvious at first: why not just add a Trigger on the control, triggered by a changing value of the property "IsMouseOver" (for WPF. For SilverLight there is no "IsMouseOver, so instead we should add EventTriggers on "MouseEnter" / "MouseLeave"). When "IsMouseOver" changes, then we can then just play the adequate storyboard.
However the reality is more complex than that... The main control will receive MouseEnter and MouseLeave events (with associated changes of "IsMouseOver" ) whenever the mouse cursor enters/leaves the targeted control AND when the mouse cursor enters/leaves any of the sub-controls composing the targeted control!
Which results in a flickering display: in our example, while moving the mouse inside the scope of the product form view, the form view will be constanlty switched from highlighted to not-higlighted when for example the mouse enters the scope of a TextBox.
I have tried quite a few things to fix that issue. I registered to the MouseEnter/MouseLeave events, in order to generate custom events that will really reflect entering/leaving the main control, and hiding entering/leaving internal controls. However this was a failure and there is no easy way to really be able to know if a MouseLeave event on the main control is because we're really leaving the main control or entering a sub-control.
I have made some research to see what others are doing but could not find a satisfactory answer. I had to admit this is not an easy task on WPF/SilverLight where it just should be!!
So here is the final solution that I implemented:
The problem is really on the MouseLeave event: we have no easy way to figure out if we are really leaving the main control or just entering a sub-control. No problem on the MouseEnter event: whenever we receive a MouseEnter event it means that we are entering the main control or already are over the main control and entering a sub control. But the important point is: we know we are over the main control.
The solution is therefore the following
Only rely on MouseEnter event: whenever a MouseEnter event is received, we do the animation for Highlighting the control (and keep a flag set to do the animation only once)
We know we are leaving a control, when we are entering another one (in our example we know we are leaving the product grid view when we are entering the product form view.
So: when a MouseEnter event is received, in addition to do the animation for Highlighting the controlwe, we also do the animation to remove higlight from all other controls
That's it! It is working great!
And a few quick tips for doing it on WPF, using the MVVM pattern:
Add an "IsActiveView" Property on the ViewModel of each composite control
In the main page loaded event, register to the composite controls MouseEnter events, and in the handlers: set/unset accordingly the "IsActiveView" property of each control
Create DataTriggers binded on the "IsActiveView" to trigger the appropriate animation
Recent Comments