Introduction
In the WPF world, we always like to separate View and ViewModel parts and we like to use MVVM pattern to accomplish that. But sometimes, we also need to have an independent View-ViewModel part which divides a part of the work to an independent module. Why do we do this?
If possible, we should classify our events defined in our .xaml. Because some of the events work only for UI changing, some others serve for business logic layer. In some cases, we could band these business events with a ViewModel, but sometimes we don’t want to make our ViewModel
confused that one ViewModel contains more than two business logics. Especially when ViewModel does just updating of UI’s data source.
In the case above, we could use Behaviors to separate an independent logic of business layer mission with UI events. We don’t care anymore about the relationship between View and ViewModel, because I do my job and my business is almost nothing relative with others. (But here, please make sure about the requirement with your team so that you’ll really not have a conflict.)
Background
In one of my projects, I defined my ViewModel to be the part which does only updating of UI data source, nothing else. My UI part provides several click-event functions which use selected data row to do some other operations. These operations will not influence directly UI’s data source. Other events and click-events in the UI part serve only for change of UI, they don’t touch business layer.
Using the Code
Blocks of code: Behaviors was injected into a BarManager
. BarManager
contains a TreeListControl
. TreeListControl
contains a ContextMenu
which referenced BarManager
’s barButtonItem
. If one of the barButtonItem
s in the ContextMenu
is clicked, ContextMenu_ItemClick
event will invoke directly Business layer functions to react user’s click. And this behavior is used for only its corresponding business layer, not for anything else.
public class ContextMenuBehaviours : Behavior<BarManager>
{
private TreeListControl _treeListControl;
private BarManager _barManager;
protected override void OnAttached()
{
AssociatedObject.Loaded += new RoutedEventHandler(AssociatedObject_Loaded);
}
void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
if (_barManager == null)
{
_barManager = sender as BarManager;
_treeListControl = _barManager.Child as TreeListControl;
var barButtons = _barManager.Items.Where(p => p is BarButtonItem);
foreach (var button in barButtons)
{
(button as BarButtonItem).ItemClick +=
new ItemClickEventHandler(ContextMenu_ItemClick);
}
}
}
void ContextMenu_ItemClick(object sender, ItemClickEventArgs e)
{
try
{
if ((sender as BarButtonItem).Name != null && _treeListControl != null)
{
string clientName = (_treeListControl.SelectedItem != null) ?
((_treeListControl.SelectedItem as UIOrder).CLIENTID ?? "All") : "All";
switch ((sender as BarButtonItem).Name)
{
case "PretradeBarButtonItem":
ContextMenuEvents.RunPretradeBarButtonItem("", null);
break;
case "PosttradeBarButtonItem":
break;
...
break;
case "CreateExecutionBarButtonItem":
ContextMenuEvents.RunCreateExecutionBarButtonItem(_treeListControl);
break;
default:
break;
}
}
}
catch (Exception exp)
{
EXOE.ExoeManager.Core.Log.ExoeToolLog.Fatal(exp);
}
}
protected override void OnChanged()
{
base.OnChanged();
}
protected override void OnDetaching()
{
_treeListControl = null;
_barManager = null;
GC.Collect();
base.OnDetaching();
}
}
Here’s a piece of code of how behaviors is used:
Points of Interest
Why do I like to separate another logic part like what I wrote above? Because there are several advantages:
- More chance for parallel teamwork (development and test), save more time or make the program more robust.
- Easy to find problems when errors occur.
It’s also a disadvantage that we should be more careful about teamwork communication in this case.
History
First version, please give your suggestions and comments.