WPF: LostFocus event on a particular control/view/viewmodel - wpf

I'm working in WPF using the MVVM pattern, and generally things seem to be working pretty well, as I wrap my brain around the nuances of both WPF and MVVM. However, I'm currently stuck on a particular issue. My actual application is fairly complex, so to simplify, let's take Josh Smith's near-defining article on the pattern and use the application therein.
Consider Figure 2, and imagine that the user has typed some stuff in the first and last name fields. Then the user clicks away from the workspace (viewmodel) entirely, either by clicking a different customer tab, or possibly a completely different viewmodel in the same application. In this case, what I'd like to have happen is for the application to ask "Hey, did you want to save your changes? Yes/No/Cancel" and respond appropriately. This has presented... challenges.
Because I'd like the user to be able to 'cancel' that first-pass suggests needing PreviewLostKeyboardFocus (since I could set Handled=true and cancel the focus shift). However, several user actions (such as clicking the tab of a different workspace) don't shift keyboard focus. LostFocus covers me better in that respect, but that's only after the focus has already been lost (though of course I could switch it back?) and there are issues with determining if the event was from the view itself (i.e., we're leaving the whole view) or if it's simply bubbled up from some contained object.
And big picture on all this - this seems to be an issue for the view, but then that implies writing code in the view rather than the magic viewmodel. Which makes me think i'm not looking at this correctly.
So I'm hoping I'm missing some big conceptual a-ha that will make all this clear. Help?

You need to concentrate on your model rather than your view. That is, what does change that should trigger your logic? In this case, I'd say it's when an attempt is made to change the active tab.
So you need an overarching view model whose responsibilities are:
Expose a collection of all sub view models (each of which appears in its own tab)
Track the active (selected) sub view model (ie. the active tab)
Your view would bind to these properties in the usual way:
<TabControl ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}"/>
The SelectedTab property would apply your logic as follows:
Is the current tab dirty?
If so, prompt the user via a service
If the user cancels, don't change the active tab
If the user saves or discards changes, then change the active tab
I think the key thing you're missing is the overarching view model. Working your way through my ActiveAwareCommand sample project may help increase your understanding.

Related

DataGrid and MVVM with Undo/Redo

I'm playing with quite simple interface with buttons and shortcuts for adding, inserting and removing rows of datagrid (underlying bound collection).
There's also a need to implement undo stack.
But...I have no idea how to do with internal logic of this control.
By default DataGrid can remove or add new row automatically and performs many other things on user input (Esc,F2 and so on) thus implicitly changing the bound data.
As commands are to be executed on the VM side undo stack is its (or even M's) business either, yet DataGrid contains internally predefined bindings to DataGrid. commands. And I see no easy mean of 'watching' the changes to the data.
My understanding of the ideal MVVM flow is like that:
User action (View) -> Command (VM) -> Commmand Excution + Undo stack operations. (VM-M)
-> UI changes respectively to VM changes.
I'm confused and need some good advice concerning the implementation.
2 Ways to go about this:
Have your all logic on the ViewModel (POCO Models).
You'll have to have your ViewModel contain an Undo/Redo stack. How you implement it is up to you, but I'd suggest just having the Undo/Redo stacks be of Tuple<String, Object>. Store the property name and the value of the property. It's easier than managing clones. It also gives you the ability for a poor mans "dirtiness" check by seeing if the UndoStack has any items on it.
Give your models some interfaces such as IUndoRedo (Rich Models).
You'll have to have your ViewModels call interface methods to Undo/Redo, but the idea is the same... have an Undo/Redo stack that is composed of Tuple<String, Object>.
If you do decide to want to have a rich model approach, you can look at existing frameworks out there such as CSLA.Net which is made for rich models, though it might be a bit more than what you'll really need. Just throwing it out there in case you want to have really rich models.
A side note: You're ObservableCollection (ItemsSource) should be of ViewModels, not Models. Just throwing that out there in case you were using the Models. That is, don't do ObservableCollection<IEmployee>, but rather ObservableCollection<EmployeeViewModel>. It makes things easier, much easier and more reusable!
Another side note: try to avoid the DataGrid. It makes developers wanna rip their hair out. I'd just roll out your own "Grid" with ListView :)
Normally I build the undo logic into the models themselves. Get them completely working the way you want before you even start thinking about how they are going to be bound to the UI.
I have done an article about undo / redo in MVVM. It is divided in two parts: the first explains undo / redo in general editions and the second explains working with lists:
Part 1: Using the Viewmodel pattern to provide Undo / Redo in WPF
Part 2: Viewmodelling lists
The flow is: User action (View) -> Command (VM) -> Commmand execution modifies the Model -> Model notifies changes to VM -> VM notifies changes to the view.
This way if the model is modified from other source it also refresh the view.
There is also a github project here.
Since your DataGrid is bound to a collection, you can monitor changes to the Collection itself instead of the DataGrid. Use the CollectionChanged event on your collection to watch for added or removed items, and register a PropertyChanged event on all of your collection's items for monitoring edits.
An alternative idea would also be to provide a RevertChanges command instead of UndoChanges. Its much simpler to implement because you only need to store the original collection so you can restore it if needed.

A better way of managing a forms state?

I am new to Windows programming, as in my previous work I've mostly been involved with web technologies, and mostly in the backend. I have inherited a Winforms application, and one of my biggest nightmares is navigating through the endless states a form can be in.
To give you an example, a form has the state 'New' and 'Edit' depending on whether the user decided to Add or Edit a record. On this form, we have logic. If this texbox has a certain value, then these other textboxes are disabled, etc. This leads to endless chaining of these rules. So, a textbox's TextChanged event will influence another field. It in turn will fire X event that changes the state of other controls. It quickly devolves into a tangled mess that is impossible to maintain.
There has to be a better way... something simple and elegant that solves this problem. Any suggestions?
What I do is to have a single method called FormatControls(). In this method, I implement all the logic such as myTextbox.Enabled = mycheckBox.Checked and so on.
I call this method from my event handlers in the form, such as on checked changed, etc... I also call it when appropriate (ie, form newly loaded with no data, record loaded from database, etc). This has suited me well for many years now, it makes everything less complex.
You are correct, if you do not have a pattern in use it can turn into a too-complex thing.
You can try to use tha Application.Idle event to perform the enable disable logic and insulate this part from the business logic part.
Depending on what controls you have on your form, you might be able to do away with the separate textboxes and add/delete buttons and replace the whole works with a DataGrid.

Switching between view mode and edit mode in MVVM?

I am new to MVVM and I've decided to move on and start adopting it in my upcoming projects.
I have read this related question and answer, but I don't know how this would be implemented with MVVM.
I want all the views in my project to have 2 modes, Edit Mode and View Mode.
I don't want the user by default to see TextBoxes for all the fields, I rather want them to see TextBlocks (or set all the TextBoxes' as IsReadOnly property to true (via style etc. you tell me..).
When the user opens up the entity it should usually be TextBlocks, Labels (or readonly TextBoxes) etc., and if he clicks "Edit" (if he has permission to), it should go Edit Mode, and all the fields' labels should be inverted to TextBoxes (RichTextBoxes etc., ComboBoxes or any other editable fields that are not just labels).
I am pretty sure I am not the only one having this issue, I would like to hear from the experts what is the most efficient way to switch between these modes in pure MVVM, and whether it's is common to declare two separate views for it.
Please refer me to a good article that explains how to do it (maybe it is done by Visual State?? IDK).
UPDATE
I want to know WHAT rather than HOW, my question is about the pattern, and is should I separate Edit Mode
from View Mode at either the V or the VM?
So please emphasize this detail in your answer.
Thanks in advance.
Use the IsReadOnly property for your text boxes and bind that to the "edit mode" property:
<TextBox .... IsReadOnly={Binding IsViewMode} ... />
Then in your view model:
public bool IsViewMode
{
get { return _IsViewMode; }
set
{
_IsViewMode= value;
// Call NotifyPropertyChanged when the source property is updated.
NotifyPropertyChanged("IsViewMode");
}
}
IsViewMode defaults to true and is switched to false when the user clicks "edit". The binding will instantly make all the text boxes editable.
You could do the same for the other controls - though it will be the IsEnabled property you need to bind to in these cases - though you'd have greyed out controls.
To swap out text blocks and your controls you'll need to have both controls sharing the same location in a grid and their visibility controlled by the IsViewMode property via a pair of converters:
<TextBlock Grid.Row="1" Grid.Column="2" ...
Visiblity={Binding IsViewMode, Converter=DirectConverter} ... />
<ComboBox Grid.Row="1" Grid.Column="2" ...
Visiblity={Binding IsViewMode, Converter=InvertedConverter} ... />
The direct converter is:
return IsViewMode ? Visibility.Visible : Visibility.Collapsed;
The inverted converter is:
return IsViewMode ? Visibility.Collapsed : Visibility.Visible;
I think about it this way: the View is what it looks like, and the ViewModel is how it interacts with the user. Since a readonly interface has substantially different behavior than a read/write interface, then there should be two different ViewModels.
Now I did created an edit ViewModel that inherited from a display ViewModel because I considered the editing functionality to be an extension of the display functionality. This works for simple CRUD type applications where the user is directly editing fields without a lot of business logic.
On the other hand, if you have a more complicated business process (or workflow) that you're modelling, then typically the way you manipulate information is very different from the way you want to view it. Therefore, I would generally separate the two ViewModels unless it was just CRUD.
ChrisF's answer is fine if you want to go the IsReadOnly route. If you want to go the TextBlock-to-TextBox route, though, the most efficient way is have a Control which switches its Template, via triggers, based on the value of an IsInEditMode or IsInViewModel property.
Viewmodel: I would definitely keep just one viewmodel with a ViewMode property much as described in ChrisF's answer. Separate ViewModels would just be inelegant.
View: As I see it, you have at least three options, with various pros and cons.
Just readonly-ing all the controls, as suggested in the ChrisF's answer. Pros: Simplest thing to do. Cons: That is an ugly UI in my humble opinion.
Create seaparate display and edit controls in separate containers. Bind visibility of the containers to ViewMode. Pros: A more pleasing ui experience can be afforded here. You can even animate the transitions from one to the other. Cons: Doubles the number of controls (could hurt performance for very large windows). Positioning the controls inside the two containers at exactly the same pixel positions can become a bit non-trivial in a fluid ui.
For every edit control in the xaml, position a display control right on top of it. Bind visibility to the ViewMode property. Pros: No duplication of label controls at least, so slightly faster. Cons: Harder to get animation stuff and other view tweaks right.
Edit: In view of the clarification provided, I chose to replace the previous answer as it pretty much largely dealt with the how and not the what.
First, I'd implement an abstract base class for my view models that implemented IEditableObject and exposed appropriate commands for BeginEdit, EndEdit, and CancelEdit. It might be that the actual implementations for those three methods would have to be up to the derived classes, but the commands could live in the base class.
In this approach, EndEdit updates the model with the current values of properties in the view model.
I'd also implement a boolean IsEditing property in the base class, for use in data triggers, so that if I want to switch between modes without (say) opening a modal dialog, I can just do it in a style.
As far as the visual design of the front-end goes, I find the idea that a read-only view is just an edit view with read-only controls is one that appeals primarily to programmers. Generally speaking, if you're simply presenting an object to a user, the goal of that presentation is to provide the user with an informative, clear, and intuitive representation of the information in that object. If you're letting the user edit an object, the goal of that presentation is to make the task of modifying all of the editable properties of the object as easy and clear as possible.
Those are two very different sets of goals. For instance, while a person's sex, height, and weight might be important pieces of information for an application to collect, it's probably not all that important for the system to present that information to the user in most contexts. It seems like a very natural thing to do if what you have in your head is that edit mode is just like display mode. But if you're placing the needs of the user, and not the programmer, front and center, it may not be the right thing to do at all.

Put it in codebehind or in the ViewModel

I would like to get some opinions on when/if it is ok to put code in codebehind. I've only been at this for less than a year now. So, I still consider myself very "green". I come from a Delphi background. So, the learning curve has been tremendous to say the least – learning WPF, XAML, C#, Unity, Prism, MEF, .NET, MVVM, etc… Fun but very challenging.
When I first started less than a year ago, the idea in the office was no code in codebehind if at all possible and no view specific code in the VM.. So, I have racked my brain many times to determine how to push literally everything into the VM and keep what I think is view specific code out of the VM only to come up short almost every time. I’m to the point now, I’m beginning to think codebehind is not always bad or “wrong”. I have recently been trying to clean up some of our views by attempting push any codebehind into the VM which led me to find a neat factory class at http://blog.functionalfun.net/2008/09/hooking-up-commands-to-events-in-wpf.html. This allows you to bind routed events to ICommands in the VM. It works like a charm and I was able to significantly reduce some of our codebehind with it. However, after doing so, I’m now questioning my decision to do so. My approach followed the philosophy that codebehind was bad/wrong unless absolutely required. Now that I have had a little time to think about it, I’m not so sure the refactor was the best idea.
The following is an example of a view I refactored. We have a new account view where the user enters an SSN and must rekey the SSN before the new account can be created. The view has a label that displays text to tell the user if the SSN and rekey SSN do not match and the OK button is not enabled until they both match. Once the SSN and rekey SSN match, the label disappears (yes I know… I hate that but I’m just the developer) and the OK button is enabled. So, the hiding/showing of the label and enable/disable of the OK button is triggered from the TextChanged events in the SSN and rekey SSN text boxes. Initially I had logic in codebehind to compare the two textbox values and set viewmodel properties appropriately to update the visible property of the label and the OK button’s enabled property (yes their properties are bound in XAML). After finding this new factory class, I used it to push all of the code into the viewmodel and the view works just like it did before just without codebehind. After successfully refactoring the view, I am now second guessing the decision to refactor.
My concern is, what if we want to have a different view in the future and the new view doesn’t want to handle mismatched SSN’s in that fashion. Maybe the new view would allow the user to type in mismatching SSNs and then display an error message when the OK button is clicked. Should the new view have to accept the extra overhead of code in the viewmodel executing for every keypress in the text boxes? That just doesn’t sound right to me. I’m starting to think the viewmodel should contain what is required to support what the view needs but not do everything for the view. The view should be able to make decisions based on something in the viewmodel but not depend on the VM to hold its hand – right?
The XAML and matching .cs file make up the view. Because of that there's nothing wrong with putting code in the codebehind as long as it's for the view itself.
There is certainly nothing "wrong" with codebehind.
Here's how I'd handle your SSN example:
Bind both SSN fields to properties on the view model
Bind the OK button to a command in the view model (I'm a big fan of the Delegate Command concept)
The command should implement the CanExecute portion and only return true when both SSNs match.
It doesn't seem that the SSN matching is a view concern, it's a business practice. It belongs in the view model. What would be in the view is how your application shows that the SSNs do or don't match.

WPF Undo Redo Property System to highlight in red color if value has changed

I have a following requirement for a very complex UI. (Complex here means there are lot of controls in the form [approximately 100]). I am using MVVM (if my problem requires it to slightly go away from MVVM I am ok with it)
My question is for Editable ComboBox and TextBox. But I would say I like to hear a common algorithm which will fit all controls.
Requirement 1 : The user edits the content and goes to next control, the color of the control/text should become red.
Requirement 2 : When the user comes back to the previously edited control and enters the value which was initially present, the color of the control/text should become back to black.
I know the requirement is tough and I have been breaking my head to design a generic algorithm using which I can store the previous value and call a function to change the color of control.
To just give you all an idea, --> I tried storing 2 properties for every TextBox like Default_Text and Text. But since the number of properties are huge, the memory footprint is very huge. Also maintaining so many properties is very tough.
--> I tried adding a Dictionary to every ViewModel to store what values have got changed. But here the problem I faced was giving unique keys to all the controls in my application, which is not very helpful
--> I had even thought and tried about subclassing controls like TextBox, ComboBox and overriding some methods to suit my requirement, but sadly I failed miserabley when I started adding validations and all.
So here I am stuck with designing a generic WPF property system/algorithm to handle all undo redo functionality, changing styles of controls,etc!!!
It will be really great if you experts can guide me in right direction and also help me in developing such an algorithm/system. A sample illustration will be nice though!!!
I found an answer to the above problem. I used attached behavior for this. More details on this link Function call from XAML from StackOverFlow.
When I databind, I store the initial value of the DataBound variable in the Tag property by using Binding=OneWay. Then I have written a attached behaviour for LostFocus event. Whenever the user enters a control and then goes to other control, it fires LostFocus event and calls my attached behaviour. In this, I check whether the value is equal to the value in Tag. If it is same, I display in black else I display in red.
Attached Behaviour rocks in WPF. I can achieve anything from that cleanly without code cluttering!!!!
Another alternative is to use some "dirty" tracking in your models (or viewmodels) and bind to a properties isdirty (and convert it to a color).

Resources