I have application full of various controls databound to my classes. I would like to ask user "You are closing application and you made some changes. Do you want to save your changes?". For this I need to recognize that user made any changes.
How to catch user made changes in databound controls? Is textBoxXXX_TextChanged the only way to do this?
Thanks in advance for all your answers.
It depends on the datasource; for example DataTable and DataSet sources contain the GetChanges() methods which allow you to easily see if rows have been added/removed/modified. Other data sources will have their own implementations, if any. If there is no implementation then it's up to you to determine how to check for those changes.
In any event this is something you should do at the data-level, not the UI (by watching for "changed" events). Watching events doesn't scale beyond a couple controls and maintenance can be iffy.
Update: Not sure why I didn't think of it, but a second option is to add a BindingSource to your UI object and use it as a databinding proxy (your UI controls databind to the BindingSource and the BindingSource binds to the real datasource). It provides a better approach than handling all your individual "Control_Changed" events, and requiring rework of your other layers (esp. if they aren't custom data-types).
You need to provide custom logic for that, there's not really an automatic way of doing this. As I see it there are several options:
At the start of the editing, save a copy of the original data object, and when you need to check, compare the current object with the saved one. The comparison can be custom (field by field) or semi-automatic by use of serialization (compare the serialized forms) - if it is serializable.
In each of your data object's property set accessors, test for a change in value and mark the object as 'dirty'.
As been discussed, there are many ways to do this depending on how granular you want to get.
A relatively easy way using client side javascript would be to do something like the following:
Hook into the onchange events of the form elements. You could do this dynamically on page load using javascript/DOM.
When the onchange error handler is called, you could set a page level variable: pageHasChanged = true;
Hook into the page's beforeonunload event (occurs when the user tries to navigate away from the page) and check the pageHasChanged variable to see if any changes were made. If changes were made you could alert the user.
This doesn't give you the detail of what changed, but would be fairly easy to modify to track which form elements changed.
Related
This question must have been solved multiple times by many people, however after several hours of research I still haven't found what I'm looking for.
What I have is a ExportSettings.settings file with a bunch of settings (bools, strings, ints, etc) and I want to create a View for them. In order to do it I've created a simple window in which I've placed standard buttons as OK, Cancel and Close and linked them to a KeyDown event to let the user accept/cancel using Enter/Escape.
I've created in XAML the needed Checkbox, TextBox, etc, for my settings. When the ExportSettingsView class starts, in its constructor I read my settings and assign the value for each control. In past I bound them directly but that unables the cancelation of changes, so I discarded it. When the user clicks OK button I assign, again, code-behind each value for each settings. If he clicks Cancel no assignment is done and the window just closes.
I would like something like EditableObject for my settings to avoid this ugly looking way of making my SettingsView.
Some of the things I'm looking for are:
Being able to put some comments in my settings would be nice (ToolTip)
Autogeneration of controls using reflection?
Avoid creating custom settings class (and the work of saving and reading everytime the application starts/shutsdown)
Break you problem up into parts to use MVVM, create your window and bind it to another class (ViewModel), this class will have properties on it that reflects the data in your settings file. this class also has to implement INotifyPropertyChanged. It can also implement EditableObject if you want, but frankly it isn't needed.
Hook you buttons up to Commands on your VeiwModel so that when the user hits save, it writes its properties to the settings file.
In this instance:
Window is your View
The new class is your ViewModel
Settings file is your Model
This will allow you to cancel changes, just dont write to your settings file when the user hits cancel.
The biggest point is that you DONT bind to your properties settings directly.
If you want auto generated fields for the view youll have to use a property grid, but with MVVM, your view is decoupled from you model so changing from things like textbox and such to a propertygrid would be easy.
When you do a search for MVVM, dont be fooled by people using a lot of terminology, MVVM is a very simple concept, it boils down to three classes, your View (xaml), View Model (what the view binds to) and Model (your data), THATS IT! good luck
I think you need something like this http://wpfdataform.codeplex.com/
And if you use ReSharper you can easily generate wrapper class for your settings
.NET already supports very nice tool for saving application and user variables. http://msdn.microsoft.com/en-us/library/aa730869(v=vs.80).aspx
It has to be saved explicitly so it might suit you very well. You can check what type the variable is and create a suitable control.
I am having a form with different type of controls like Text Box, Drop downs, Check box, Radio buttons etc. All these controls are loaded dynamically from database at run time.
I want to perform validation on Text box on conditional basis. For example, If we have selected any value in drop down, then you must have to fill details in Text box. Otherwise text box details are not required.
I am open to use database to perform this task and I am using MVVM pattern in my project.
Any help on this is highly appreciated.
Thanks.
(I started this as a comment, but it ended up being too long).
In theory you have access to all these controls and their values in your ViewModel.
Without knowing the specifics of your program, it's difficult to suggest anything useful, but in essence you need to expose some more properties from your ViewModel (probably boolean) which will be calculated based on the values in your controls. Then you need to bind IsEnabled properties on your controls to these new properties.
Sounds simple, but I think you have some architectural problems which will make it difficult to implement what I suggested above. In order for this to work and automatically update your controls whenever other controls' content change, your ViewModel needs to implement INotifyPropertyChanged and raise PropertyChanged event every time you update one of those boolean properties.
I think what you're trying to do could be achieved with ItemsControl and DataTemplates (and maybe DataTemplateSelectors). This will allow you to store "data" in your ViewModel (say List or something more specific) without referencing the actual Controls and the relevant DataTemplates will add the right controls for different data types you have in your ViewModel.
How can I check if any control (check box/radio button) of the currently active form has been selected/toggled?
My goal is to create an option called Save changes automatically which would enable saving the current state of check boxes and radio buttons, so I need to know when any control is selected/toggled (to execute the save settings method). I don't want to create a separate event handler for every control, I'm looking for a generic solution if it is possible.
This is not a job for the user interface.
Use databinding to change a Model in code-behind and let the model trigger/escalate changes.
To help you on your way a little:
Your checkboxes and other controls are not where your data is. They should only show the data.
Create an object (the Model) with boolean properties for the checkboxes and int/enum properties for the radioboxes. Set up the databindings from the controls to the properties.
Then you can implement the necessary logic in the Setters of the properties.
As Henk proposed, you could use a Separation of Concerns pattern such as MVC to separate UI and domain logic. As the user makes changes to some UI widget, you update the value in the model, for example by setting a property. The property setters could then update a IsDirty (or HasChanges, ...) field. This property would be read by the UI which would, depending on the value of IsDirty, decide what needs to be done. (Display a MessageBox("Do you want to save your changes") or something else)
I do think that Henk was thinking web while you tagged the question with WinForms. Chances are you are not using a pattern to separate UI and domain logic. (and that UI and domain code are already so intertwined that your current deadline does not allow you to introduce a model right now)
You could achieve the same thing by placing the IsDirty field on your Form and having the Changed EventHandlers set that IsDirty value. By subclassing the Form (ie put the IsDirty on your 'FormBase') and your controls (for example by introducing a watermark), you could have this behavior out of the box for all your forms.
i have a form that is generated dynamically.
the plan is to generate it, the user to enter data, and then to save all that lot away.
although a slight variation to this is if the form has previous data associated with it, and then it loads in all pre-populated. - the user may then change any previous selections.
and that is the rub really, i know if i call generateform regardless of postback the viewstate should take over and remember what the settings weer.. but as the generateform method as mentioned above populates the form if the form has previously been saved. which will win, the viewstate or the generateform method for the field populations.. ?
thanks
nat
If you dynamically generate any form controls that post data or cause a postback, you need to recreate them again on postback in order for them to be bound to their data, or their events, after the postback. Conceptually, this makes sense. If you don't have a control in your form after the postback, how could you look at its contents?
There are several ways you could approach this problem.
1) Call GenerateForm() no matter what. Since you said it pre-populates some of the data, you would need to change it so it can be called without doing that. ASP.NET will populate the controls with the data posted automatically on postback, which is what you want.
2) Keep a list of all your dynamically generated controls in a ViewState variable, so you can re-generate them upon postback. For most situations involving dynamically-created controls that aren't very simple (e.g., you may not know in advance exactly what controls are generated), this is the best solution. And often you will want to be able to access the data after a postback, but maybe you really don't want to recreate the whole form because you aren't using it any more.
As long as you recreate a control of the same type and ID on or before Page_Load(), it will be bound to the posted data. It does not need to be in exactly the same place on your form. And it does not need to be used or displayed, either - you can destroy it before the form is rendered, e.g., in Page_PreRender()
3) If you have no interest in any of this, you can always use Request.Form to look directly at the posted data, though this can also be tricky because the names will likely not match your form control IDs exactly. ASP.NET generates unique client-side IDs that depend on the container, and this is what you'll find in Request.Form. If you don't regenerate a control, you may not be able to easily determine the ID that you are looking for. Generally, you should not do this, but it's a way to look at the posted data and sometimes you need it.
How is data binding in C# WinForms supposed to work when you have a Save button? I don't want the data updated until I press Save!
I have two forms (list and detail) backed by a BindingList<T> collection and my custom object from that collection, respectively. I can bind each form to the list or object appropriately. However, any changes made in the detail form are immediately reflected in the list form - I don't want to save the changes and update the details shown in the list until the Save button is pressed.
Is data binding designed to support this? Is there a common pattern for doing so?
Whichever way I look at it, binding doesn't seem to be able to support this scenario. I've considered the following:
Pass a clone of the object to the detail form, but then I have to reconcile the changes on Save - changes may have been made to the copy in the list in the meantime.
Implementing IEditableObject and calling EndEdit on save almost works as I can prevent the list being notified of the changes made until Save is pressed, but if something else causes a refresh the list is updated with the interim data.
I'm currently left with dispensing with data binding in my detail view, and doing it all manually. Which is rather annoying.
Data binding really wasn't designed for this kind of thing, unfortunately.
The best solution we've found here is to edit object clones, then reconcile the changes, as you mentioned. You may want to come up with a custom collection and/or object interface that helps you manage this type of thing.
Even if the cloning method is slightly more work up front, it's going to be wayyyy less complicated and frustrating than using IEditableObject trying to catch all the possible events that update the data. Not only that, it's a more straightforward approach, and you won't end up with spaghetti code.
If you are set on using a binding list, your best bet would be to implement IBindingList to create the functionality that you desire. It may also be possible to pull this off by simply inheriting from BindingList and overriding the appropriate methods to change the binding list's behavior.
http://msdn.microsoft.com/en-us/library/system.componentmodel.ibindinglist.aspx
If you are not set on using a binding list, it is probably best to do the data manipulations manually based off of the control's events.
Best of luck.