Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lost Focus Event Strategy in MVVM pattern

I’m developing a WPF application with MVVM design pattern which makes use of the MVVM Light Toolkit. Currently I have a scenario like this.

enter image description here

I’m binding an Items Control to an Organization collection.

  1. An Organization comprised of Organization Name and a List.
  2. A project comprised of Project Name, List and New Employee
  3. An Employee comprised of Emp Name, Contact No and Email

enter image description here

Here Employee itself is a user control which is reused in Existing and New Employee data.

User can update existing employee’s details (i.e. List) on every control's Lost Focus event. When it comes to adding a new employee, I handled the situation using user control Lost Focus Event. So on user control lost focus event using MVVM Light Toolkit EventToCommand, I’m passing EventArgs to View Model and then finding the Original Source from EventArgs(or traverse through the visual tree) to identify whether it’s to be inserted or not by checking whether the focus is within same user control using IsKeyBoardFocusWithin property.

Is this is the right implementation on MVVM pattern?

Also by doing the above approach I have to:

  1. Traverse through the visual tree or to get the Original Source from EventArgs I have to make reference to System.Windows.Controls.

  2. when it comes to unit testing, it would be more difficult to mock the EventArgs.

So is there any better MVVM approach to handle this scenario…

like image 957
Dennis Jose Avatar asked May 07 '13 10:05

Dennis Jose


1 Answers

As you mentioned yourself traversing through the Visual Tree should be avoided in the ViewModel

So an alternative to this approach could be using a Behavior - Tutorial

  • So let's assume you create a Behavior called AddNewEmployeeBehavior
  • Next add a RelayCommand<Employee> AddNewEmployeeCommand; to your VM.
  • Create a DP of type RelayCommand<Employee> in AddNewEmployeeBehavior
  • In the View bind the DP of the Behavior to AddNewEmployeeCommand
  • Now in AddNewEmployeeBehavior do what you were doing in the VM to check if a new item needs to be added to the List<Employee>
  • When new item is required to be added to the List kept in the VM / Model, Invoke the DP Command in the Behavior passing in the new Employee details wrapped into an Employee object.
  • In the VM, create your RelayCommand accordingly to append it's invoked-with argument to the List<Employee>

Now with this approach, you do not have any EventToCommand stuff in the View. You simply have a Behavior taking a Command as a DP and have it invoke the Command when required based on the View only conditions you have.

As for unit-testing, that's very simple now cos all you have is a RelayCommand which you can invoke when desired in your unit-test.

This will hold as a MVVM solution since you no longer have any View related logic in your VM and the Behavior handles it for the View.

VM -> ViewModel

DP -> Dependency Property

like image 165
Viv Avatar answered Sep 22 '22 18:09

Viv