So I have an app that makes heavy use of data binding. One feature in the app is a pop-up window that lets users manage some records. They select a record from a ListBox, and then they use a form to edit the properties of that record's object instance.
Users are typically accustomed to having the option to either Save or Cancel at the end of the form. Save commits the changes, and Cancel abandons the changes.
However, with the two-way data binding, the object is being updated in real-time as the field value changes.
Is there a "best practices" way of approaching the Commit/Cancel behavior with data binding within WPF? I've thought about cloning the object being edited so that the changes occur on that clone, and then the Save applies the changes to the original record, but I feel like this is something that Microsoft probably has built in already and I'm just unaware of how to use it properly.
WPF provide BindingGroup to deals with the situation you have run into. BindingGroup allow you to handle multiple value change at the same time. You can commit or cancel changes base on the result of validating all the changes at the same time but not just each one separately. And for edit transaction to work, the source(s) in BindingGroup should implement IEditableObject interface.
Related
I'm wondering is it somehow possible to save Form state in C# after application closing? I tried with List, and whenever I create an instance of Form that instance is added to List, and it's there until it's deleted. It works fine, and I can view, edit and delete saved forms, until Application is closed. So, considering that Form isn't serializable is there any chance to save List somehow, and load it later?
The Control and Form classes are not serializable. There's a very good reason for that, many of their property values are heavily dependent on the execution state of the program. Like Handle, very important but always different. UICues, depends on whether the user pressed the Alt key. Even simple things like Location and Size, dependent on video adapter settings and user preferences.
You would not want to serialize these properties. What you want to preserve is the data that was used to initialize the controls. Which of course entirely depends on your program, there is no commonality at all. It is therefore up to you to create a class that stores the state of your UI. You can make it serializable as needed and select your preferred way to implement serialization, there are many ways to do so. Strictly separating the view from the model in your code is normally very important to have a decent shot at making this work.
In the application I'm working on, there are a lot of dependencies between GUI fields. For example, when the user changes the value in a textbox, other controls on the form need to change based on the new value, which in turn may or may not trigger other changes on the form. These relationships can get arbitrarily complicated, and user requirements change frequently.
I know there are patterns such as MVC to separate out business logic into a controller, but I think the problem I'm trying to solve is different, because it is the logic itself that gets complicated. It seems the relationships can be modeled as a directed graph with each GUI control being a node. I was wondering if this was the right way to approach it and if there are any frameworks out there before I try rolling my own.
We use an 'Appearance Model' to have the controller update the state of that model, and the view updates itself based on the appearance model only.
MyAppModel.MyControl.Readonly = true;
that would be bound to a controls readonly property on the view.
so now based on some event I can flick these states on /off to change the view.
I am using a single global DataContext object for my entire application. The application should work in a network environment where multiple instances of it work simultaneously with a shared SQL database.
The database changes in one application are not reflected in other instances until I call DataContext.Refresh method. Problem is this function is time consuming and I cannot change my code back to using different datacontext objects for different operations.
What should I do to always keep the datacontext object in each application updated?
RefreshMode Enum is the correct bit. Just a matter of deciding when to use it, and using the DataContext correctly. Think of the DataContext as a unit-of-work, and flag the refresh mode when your prepairing a submit (like KeepChanges or something). In that way, the users info is pushed (or bubbles up on conflict) and it's automagically updated with the freshest stuff in the database.
I think everyone else has rightly pointed out the wrongness of a global datacontext. You'd either have to set a refresh time or give the user a button to refresh if you wanted to update their display more frequently. I don't know of another way there.
I use nhibernate to access a mysql database, and I have many -winforms- forms using databinding to modify properties of those objects. There are many –nhibernate- objects created/deleted also during the time those forms are used.
I need to implement a "Cancel" button on those forms.
I can defer the creation/deletion of objects on the database (nhibernate’s Session.Save/Delete) to the moment the form is closing. But I don’t know what to do about the changing of loaded objects’ properties directly by the user (changed by winforms databinding) or the adding/removing of objects to the related objects collections.
I’m not a nhibernate expert at all. Is there any way to mark a referenced object as “not loaded yet”, to force a refresh from the DB the next time it is referenced in any way (collections and properties) without losing the reference (kind of return the reference to the proxy object to the initial state, before the first load from the DB)?
I’m not a winforms expert at all neither. How can I know which objects where changed through databinding?
I guess a simple approach would be to use INotifyPropertyChanged on your entities and INotifyCollectionChanged or use a collection that already implements it. Then you can subscribe to those events and, at least know, if they had changed.
In any case this is an aspect of presentation I really would like to hear some opinions on.
This seems like it would be a common issue to be but I don't know the best way to solve it. I want to be able to send an Entity to a view, have changes be made to the entity in the view, but then cancel (remove) those changes if the user cancels out of the view. What is the proper way to do this.
Here are two options I have but I think there should be others that are better
1) Take an entity, create a clone, send the clone to the view...if changes are accepted, update the original entity with the clone's values
2) Send the entity to the view, if the user cancels, remove the entity from NHibernate's cache and reload it from the database
For (2), the issue for me would be that the old entity could still be referenced throughout my project after it has been removed from the cache.
Edit:
Ok, so the evict method is the way to go if I am implementing method (2). Thanks, I could not remember the details of that one. However, the issue of view objects referencing my old evicted entities makes the issue tough to deal with. I can't just have my view automatically update to a new entity without having custom code in each one to rebind when my custom eviction event is raised. And rebinding may not be trivial in certain cases. I need to think on this some more as I may be over complicating but at the moment, this method seems trickier.
I suspect I am going to be stuck with method (1) which has its own set of problems but will wait a bit longer to see if anyone else has some ideas.
Edit 2: Just found this. I think it pretty much covers the answer in detail and comes with a great demo project - Building a Desktop To-Do Application with NHibernate - http://msdn.microsoft.com/en-us/magazine/ee819139.aspx
In addition to this, NHibernate has a Session.Refresh(Object entity) function which seems to solve the exact problem. So, when an entity is changed but then cancelled before save, I can just call Session.Refresh to reload it from the database and discard the changes.
I'll go for option 1 and use what is called a ViewModel instead of your entity.
The ViewModel is representation of you model for a specific view. In the ViewModel you can mix data from different entities and pre-format values to fit the view. Is an elegant way of passing data to a view and you can accomplish what you want easily.
Using ViewModels is becoming the preferred way of working in ASP.net MVC and Silverlight / WPF.
To read more about Viewmodels: http://blogs.msdn.com/dphill/archive/2009/01/31/the-viewmodel-pattern.aspx
The best way to do this is to call the Evict method on the ISession used to load the object. This will remove the object from the session cache. and you can then reload and redisplay it.
Evicting the object from the session makes it transient detached so if there are still references to it in the project they will not be persisted when the session is flushed. How you deal with that depends on your application but I would suggest raising an event to notify subscribers that they need to re-load the object.