I have a childwindow with a number of Textboxes, Comboboxes, and DatePickers. I want to know if a user has changed any value in these (to know if I need to save to db)
One way I could think of doing this are in the 'on chg' event handlers and set bool. But if a user changes the value, in say a combobox, then changes back to the original this would still be seen as a change.
Are there other alternatives?
(note the project is not set up as MVVM)
If you don't use mvvm but still bind to an object then:
before the window is shown create a copy of the object, save it, and bind it to DataContext
whenever you need to know if user made any changes you can compare the saved object to DataContext (property by property)
I you don't use binding at all then:
before the window is shown save all fields that can be modified to a Dictionary
whenever you need to know if user made any changes you can compare the dictionary values to values of the fields
Related
I have windows form application which has several user controls - each one is displayed when the relevant option is selected from a listbox.
Some of the user controls need to have access to data stored in a different user control so User Control A needs to know a value of a textbox stored in User Control B. I have done my exposing some properties in the user control B. This all works fine when the application first loads and no values are changed.
The problem I am having is if the value of the textbox in user control B is changed it is not picked up by user control A.
Do I have to do something with NotifyPropertyChanged? Any suggestions please?
Two solutions here:
Create a series of public properties and handle passing values where the Form objects are newed up.
Create an event to communicate when things change and register an event handler in the target Form to accept the change. This is similar in theme to the INotifyPropertyChanged interface but that's only required/advised for formal databinding scenarios.
I prefer events for this kind of thing.
I have a DataTemplate(well two data templates) that I want to use as views for some
basic form viewmodels(that that contain a value and and boolean indicating whether I want to use the value).
I want to use the datatemplate(s) several times for separate form items. I think the right way to do this is to set it as the ContentControl's ContentTemplate (in that case it will have the same data context right?) but I also want to pass the label string and since the label string is part of the ui and doesn't change it seems wrong to put it in the viewmodel object. How do I give access of the label string to the DataTemplate instance?
Just like its name, a DataTemplate is used to template the Data... For example, if you have a class called MyItem which has a Name and Value and you want this shown in a specific way, you'll set a datatemplate for Item and use it whenever needed.
In your case, you're speaking about having very similar views, with only a minor change between them. This minor change (if I understood your question correctly) is not something that comes from the model or from the viewmodel but something which is entirely view-oriented (a different title for the page, for instance).
If you plan on using a different viewmodel for every view, and each viewmodel has a different purpose - I don't see a problem with adding a Title property to the VM and bind to that too (Remember, MVVM is a set of guidelines, not rules...)
If you still rather have it separated from the viewmodel, then you can use an Attached Property. Create an Attached Property called TemplateTitle, for instance, and have each contentcontrol in each view change it. The label, of course, will bind to that Attached Property.
I have a WPF MVVM data form window with data validation. A lot of the controls are text boxes. Currently, the data binding trigger is set to the default, i. e. loss of focus. This means that a field is only validated when it is likely to be filled out completely. So when deleting a number and typing another number, the transient empty value will not be displayed as input error.
But a drawback is that the Save button can only be enabled when the focus moves out of the text box. (No matter where, just out of the edited control. Assuming there is anything else focusable.) If this is the only change, the user waits for the Save button to be available and nothing happens. For the Save button, I'd like to use an immediate binding trigger. How can that be done?
Edit: Forgot to mention that my Save button (which uses ICommand) is only enabled when the input is determined modified and valid. So the data will remain unmodified until data binding updates it, and that won't happen until the focus moves to another control.
I actually had a similar question a while back and the solution I ended using was a custom DependencyProperty that kicked off a timer when a key was pressed, and only actually processed the PropertyChange notification if a specific time had passed.
This means the bound property doesn't get updated (and validated) unless the user pauses in typing for a set period of times.
The code can be found here (may need a bit of cleanup), and it is used like this:
<TextBox
local:DelayedUpdateBehavior.TargetProperty="{x:Static TextBox.TextProperty}"
local:DelayedUpdateBehavior.Milliseconds="1000"
Text="{Binding MyTextProperty, UpdateSourceTrigger=Explicit}" />
Edit: Actually this link might be better. It's a markup extension so you can use it directly from your binding. I can't remember which of these two methods I used in the past, but I know it was one of them :)
<TextBox Text="{local:DelayBinding Path=MyTextProperty, Delay='00:00:01'}" />
Assuming you're using an ICommand type interface for the button click event:
You can...Implement string properties with INotifyPropertyChanged and bind them to your textbox controls. Now in your Command canexecute method you can check to see if the property is !nullorempty.
e/ grammar
Set your Binding's UpdateSourceTrigger property to PropertyChanged. The default for TextBoxes is LostFocus.
Update: So you want to have data binding working on your TextBox and only allow numbers? Have a look at this question: Create WPF TextBox that accepts only numbers
Or use a converter and bind the Save button's IsEnabled property to your TextBox (maybe using a MultiBinding if there's more than one), and use a converter which determines if the text is a valid number and returns true or false.
I have simple SL user control. A listbox which shows all customers and on the right a number of textboxes and comboboxes that are bound to the SelectedItem (Customer) in the listbox. The SelectedItem bound to SelectedCustomer property.
I am looking for a pattern/methodology to deal with canceling changes made to the customer (in the bound textboxes and combo boxes).
The edit controls (textboxes and combo's) can be one or two way bound to the selecteditem of the listbox.
If they are two way bound, immediate changes in the textboxes are reflected in the listbox. If they are oneway bound the changes in the textboxes are not reflected in the SelectedCustomer object.
At the bottom of the edit form i have typical Save, Cancel, Delete buttons. The save button for instance would take the SelectedCustomer object (if twoway bound and I would send through service for saving on server).
If the textboxes are one way bound i have to capture somehow the textbox values and insert into some object for sending to the server for saving.
If I use twoway binding , and say the save operation fails...i have to set the SelectedCustomer values back to original values otherwise the client now continues to see data that has not been saved.
There must be an easy way of dealing with this type of scenario....
RIA Services with Entity Framework already provides this functionality, basically how RIA services works and you can do it too as follow.
Each class implements interface called IEditableObject, which provides methods BeginEdit/EndEdit and CancelEdit. And it also stores (copies) instance of same class with name "OriginalEntity" with same values that were loaded from server.
After the form shows up for user to modify, BeginEdit is called, which probably caches every property using reflection, in some sort of dictionary. If you call CancelEdit, then values from OriginalEntity are loaded back in object.
Upon some errors while saving changes, you can either refresh the entities from server (best way) or you can try loading properties back from OringalEntity property.
I wouldn't discard user changes, as that easily leads to user frustration. IMHO, the user should not be informed about connection problems by uncontrolled data rollbacks.
I am having a number of controls in my application(which user can add to canvas), each having various properties(mostly dependency properties). User can change its properties through property grid(like color, text etc.).
I have save functionality implemented, so if user makes any change in canvas we ask him to save the document before leaving. At present I am keeping track of Add/Delete/Resize like operations(changing IsChanged flag to true). I also want to keep track of any property changes done by user, say if he changes the color of control through propertygrid.
One straightforward solution is to handle PropertyChangedCallback for each proeprty and set the flag in that. Problem with this is that I will have to write PropertyChangedCallback for each proeprty in each control, and at the same time I will have to make sure that every new proeprty added do the same.
My question: Is there any other better way of tracking property changes, say at some global place?
If your objects/classes are DependencyObjects, you could create your own 'base class', deriving from DependencyObject which overrides OnPropertyChanged:
http://msdn.microsoft.com/en-us/library/system.windows.dependencyobject.onpropertychanged.aspx
In the implementation you could register that the object had changed in some singleton or associated change-tracking manager class, then call base.OnPropertyChanged.
Then change all your objects to implement this new class rather than DependencyObject and when any properties change your code will get called.
Hope that helps!