Introduction
I was thinking about how to let people accept my idea, so I updated my tip with a new introduction chapter. What I want to tell you is that:
In a View, a button's function could be: Get values from a UI element and send the value to a long-distance machine. If this operation hasn't any relation with other business module (event no relation with other UI element at the time button is clicked), would you really like to mix it in your ViewModel
class? Or you keep a business function stay in your View
? Or will you use a Model
class?
My answer is "Behaviors to a new business module".
Original Introduction
In WPF's 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 an independent View
-ViewModel
part which divide a part of work to an independent module. Why do we do this?
If possible, we should classify our events defined in our .xaml. Because some of events work only for UI changing, some others serve for business logic layer. In some cases, we could band this business events with a ViewModel
, but sometimes we don't want to make our ViewModel
to be confusion 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 which is almost nothing relative with others. (But here, please make sure about the requirement with your team 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 barButtonItems
in the ContextMenu
is clicked, ContextMenu_ItemClick
event will invoke directly Business layer functions to react to 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 I like to separate another logic part like what I wrote above? Because there are several advantages:
- More possible for parallel teamwork (development and test), save more time or make program more robust
- Easy to find problem when errors occurred
There is also a disadvantage that we should be more careful about teamwork communication in this case.