A better way of managing a forms state? - winforms

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.

Related

How to determine if WPF TextBox is dirty (when using UpdateSourceTrigger=LostFocus)

How can I determine when a user has updated the text in a textbox before the Binding has updated the source?
I was expecting to find an "IsDirty" property on either the TextBox or the Binding ...
My problem is that the "Cancel" button Enabled property is bound to the ViewModel's IsDirty property and is disabled until the focus moves out of the textbox.
"IsDirty" needs to be defined as ViewModel.IsDirty || TextBox.IsDirty
WPF can't support the typical IsDirty behaviour that users would expect in a high quality application.
The problem stems from the strange design of the Binder class.
Furthermore WPF architecture is kind of hard-coded to using the default Binder implementation, replacing it is a huge job and requires many "dirty tricks" to work around the endless WPF design flaws.
The easiest way I found to workaround this limitation is to move all value conversion logic to the view model and use UpdateSourceTrigger=PropertyChanged, and implement your own IsDirty and IsInvalid logic and flags.
This approach also plays nicely with Caliburn.Micro
First, why is Cancel disabled? It should be enabled all the time. Any other behavior would be odd. The user should be able to cancel although he hasn't done anything.
Second, I would use Commands so that it can determine whether it can be executed or not based on the state of the viewmodel. Should be easy to implement, if the viewmodel also provide the implementation of the command.
I'd recommend to read some articles and/or tutorials about it. Google for the interface ICommand.
And to answer your question. Assuming you're using binding you could use the INotifyPropertyChanging interface to determine when a value is about to change. You could then store the current value in a backup field or something.
EDIT - Regarding "let him lose data"
Sure it's a valid strategy. Think on a larger input dialog e.g. 5 input controls, which must be validated before persisting the input. I'm assuming that the data is very important according to your arguments. Furthermore, you started to hack your data into the dialog. On input control 3 you decide to press 'ALT + F4'.
First, ask yourself, why did the user press the keys? IMHO he doesn't care about what's happening to his data.
If 'ALT + F4' is just an example for being robust. Forget about it. I think absolute robustness cannot be implemented without being very expensive.
Second, regarding consistency and validity after the restart of the application, you have to throw the data away so that you don't start with an undefined state. Remember, the entity the user began to fill is not valid at this state. Neither the states respectively the values of the properties are.
So IMHO the much better strategy is to restart with a clean and defined state, so that the user is able to continue with whatever you want him to do with your application.
Why is this strategy better? Well, it's much easier to implement. And the much more important argument, the user never gets lost because of an odd state.

Passing params through nested user controls in Silverlight 4

I have a three level of nested user controls in my Silverlght 4 application.
the most low level control fires an event with some parameter, then second user control takes the parameter and also fires an event sending parameter to up. Third user controls makes same thing passing parameter to the MainPage. Anyway a have got my parameter but the way I did it very boring and confusing. Is there any acceptable and easy understanding way to do same thing shorter.
Thanks a lot!
That is the correct way, mainly because any level is replaceable and so should function the same way.
Boring and simple looking are actually good things for code... makes it easier for others to follow.
If you want excitement... I would suggest a career change :)
It all depends on what the event is and what the parameter you are bubbling up contains. If this is purely user-interaction and the visual parent needs to react to your event, then, as HiTech Magic mentions, this is the best way to do it.
Now, if what you are trying to do is actually related with the business logic of the application, then maybe your user control is not best place to handle this event and you may benefit from binding a view model to your user controls and using some kind of event aggregator to broadcast your events.
It may be good for you to add more context to the event your are firing and the parameter which you are bubbling up to the container for you to get additional information which applies to your context.

How to get an event when WinForms TreeView items gets cleared

I am using a standard TreeView in a WinForms application and everything works fine except for one issue:
Parts of the system need to change depending on the selected TreeNode, which works fine using the AfterSelect event.
However, sometimes the TreeView will get cleared completely resulting in an empty selection which does not trigger this event.
At the momemnt I am calling the event callback manually to fix this issue.
This is obviously dangerous, since I will forget to call this function somewhere. Is there a "correct" way to do this?
Thank You!
This is by design. The underlying native Windows controls only generate notifications for things you cannot figure out yourself. The ListBox control for example doesn't have any event that tells you an item got added or removed. Which is because there is no way for the user to add or remove items. Similarly, there's no way for the user to remove the nodes from a tree view.
These kinds of changes requires code that you write. Since it is your code, you cannot not know that these changes happened. If you want an event then you'll have to raise it yourself. Beware that this is harder than it looks, the TreeNodeCollection class doesn't reliably let you generate an event for programmatic changes to the node collection. It doesn't behave like an ObservableCollection. You are definitely better off by not needing this event.

What's the "right" way to isolate control dependencies

I've made it a personal rule to inherit every UI control before using it. In a previous life I'd always considered this one of the less useful things you could do because the justification always seemed to be "I might want to change the font on all the buttons at once"... a motivation that never paid off... once... ever.
Two recent projects have changed my mind about the practice, though. In the first, we needed a consistent "ValueChanged" event so that we could easily implement a "dirty" flag on our forms without a massive switch statement to choose between a Textbox's "TextChanged" event, or a ListBox's "SelectedIndexChanged" etc. We just wanted one consistent thing to listen for on all controls, and subclassing the built-in controls bought us that pretty easily.
In the second project, every effort was made to get by with the base controls because the UI was expected to be pretty simple, but a few months in, it became obvious that they just weren't going to cut it anymore, and we purchased the Telerik control suite. If we had inherited all the controls to begin with, then changing our derived controls to inherit from the Telerik controls would have applied the changes for us globally. Instead, we had to do some searching and replacing in all the form designers.
So here's my question: What are the relative strengths and weaknesses of
Simply adding a Class, and making it inherit from a control.
Adding a new "Custom Control" and inheriting.
Adding a new "Component" and inheriting.
All three have the same effect in the end, you get a new type of Button to put on your forms. I've seen all three used by different people, and everyone seems to think that their way is the best. I thought I should put this discussion on StackOverflow, and maybe we can nail down a concensus as a community as to which one is the "right" way.
Note: I already have my personal opinion of which is "right", but I want to see what the world thinks.
If both 1 & 2 are inheriting, then they are functionally identical, no? Should one of them be encapsulating a control? In which case you have a lot of pass-thru members to add. I wouldn't recommend it.
Peronally, I simply wouldn't add extra inheritance without a very good reason... for example, the "changed event" could perhaps have been handled with some overloads etc. With C# 3.0 this gets even cleaner thanks to extension methods - i.e. you can have things like:
public static AddChangeHandler(
this TextBox textbox, EventHandler handler) {
testbox.TextChanged += handler;
}
public static AddChangeHandler(
this SomethingElse control, EventHandler handler) {
control.Whatever += handler;
}
and just use myControl.AddChangeHandler(handler); (relying on the static type of myControl to resolve the appropriate extension method).
Of course, you could take a step back and listen to events on your own model, not the UI - let the UI update the model in a basic way, and have logic in your own object model (that has nothing to do with controls).
I use composition. I simply create a new UserControl and add the controls I need. This works fine, because:
I never use that many properties anyway, so pass-through methods are kept to a minimum.
I can start with a naive approach and refine it later.
Properties for look and feel should be set consistently across the site. Now I can set them once and for all.

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

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.

Resources