How to restore changed properties of a data binded object? - c#

I'm stuck and I hope for suggestions. I'm talking about only in-memory objects. No databases or files involved here.
Basically I have an object whose properties I've bound to some text- and combo-boxes. When I change the value in a texbox, the value in the bound property gets also changed, obviously. What I want to achieve is, that when I change the value in a texbox, the change should be made only temporarily.
This is what I do:
I load my data and then the main form gets opened with a list of all my data items. I double click an item and another form gets opened where I bind the properties of the item to some textboxes. I change something and click cancel. Now if I open again the same item, the changes are still there.
I want the changes to be temporarily so only if I click save, then the item should be updated. I can't figure it out, how to do it with a data bound object. I guess I miss the point of Databinding?
I could make it easy by assigning the values of my item properties to the textboxes and write the values in the texboxes back to the item properties as I click save. But isn't Databinding made for this kind of work or am I completely off?
Should I query my database again to restore the original data of that specific Item, if I want to use Databinding?
Edit: As suggested in the comments, I can use a copy of the item and save its changes to the original item, as I click save. But what is a good way to enforce that the form is working with copies of that item only? The view should not need to know whether its a copy or not or that it should make a copy first.

Related

Best way to lazy load with TemplateStudio WinUI ListDetailsView

I started a project using TemplateStudio for WinUI (C#) 5.2. It uses the CommunityToolkit ListDetailsView Control for a "List Details" page.
What is the best way to load additional data when a user selects something from the list of results? I thought I would add two more properties to my ViewModel (one to handle the data, one to show a busy animation while the data is loading, both using ObservableObjects SetProperty), when the selected gets changed I fetch the data async for the selected item and update the ViewModel properties accordingly.
I can't seem to find a way how to access this data from the DetailsViewControl, and I'm not sure I do it the correct way anyway.
If I add a property to my model and change the value on changing the selected the data gets added, but the UI doesn't update itself (I tried _selected and Selected). Only when selecting another item from the results and going back to the previous shows the value.
What would be the best/correct way to lazy load additional data with this control? There would be about 4-5 parallel requests going on in the first release.
Later on I need a few buttons in the DetailsViewControl as well, where and how am I supposed to handle the commands?
Or am I better of not using this control and do it manually?

Why doesn't the dropdown of the combobox not update when I change the ItemsSource?

While trying to alter the contents of a combobox on runtime, I stumbled upon a confusing feature.
(Please excuse the many images. I felt that they were severely needed to understand what's going on)
Above you can see my WPF form, my xaml and the codebehind for the Button_Click_1 event.
Incase you were wondering what strings were exactly being saved into this "txt" variable, it was "jon", "ted", "tod" and "adam". As you might expect "jon" would have the index of 0, "ted" of 1, "tod" of 2 and "jon" of 3.
What I want to do is change the "List" assigned to the "ItemsSource" directly without having to reassign a new "List".
What I noticed while testing was that this is definitely possible.
Below you will see the results of me clicking on the button once.
What essentially is happening is that the content of the "test.txt" file is getting saved into the the "txt" variable as a "List".
This variable is then assigned to the "ItemsSource" property of the combobox.
I then proceed to alter the "ItemsSource" directly by removing the item with the index of 1 ("ted").
Lastly, I set the "SelectedIndex" to the item with the new index of 1 ("tod").
When running the program and clicking the combobox to see what items are contained inside the dropdown, I am presented with exactly those three items contained inside of the altered "ItemsSource". ("jon", "tod" and "adam")
Now it starts to get a little more confusing when I decide to click on the button again.
As you can see, after clicking the button a second time, all four items of the "List" get displayed instead of the previous three.
My current theory of how the dropdown of a combobox works is that the content of the "ItemsSource" property gets saved into a sort of cashe which gets used by wpf internally to display the items of the dropdown. This saving of the content seems to also only happen on the first click of the choicebox (textbox). It is then no longer possible to change this cashe by altering the "ItemsSource" directly. Through further testing I also discovered that the only way to change/update this cashe is by assigning a whole new "List" to the "ItemsSource".
Is my theory in some way, shape, or form correct?

Can't refresh datagrid

I have a DataGrid, which loads the data on start up. There are several buttons on which the user can click. Each button updates the same column. The problem is that when the new value of that column is saved, the old value is still shown in the data grid. It must be refreshed. I have tried several ways to do it, like: t_KlantenDataGrid.Items.Refresh() and CollectionViewSource.GetDefaultView(t_KlantenDataGrid.ItemsSource).Refresh(). None of them works.
The code which loads the data:
OV.AOVDataSet aOVDataSet = ((AOV.AOVDataSet)(this.FindResource("aOVDataSet")));
// Load data into the table t_Klanten. You can modify this code as needed.
AOV.AOVDataSetTableAdapters.t_KlantenTableAdapter aOVDataSett_KlantenTableAdapter = new AOV.AOVDataSetTableAdapters.t_KlantenTableAdapter();
aOVDataSett_KlantenTableAdapter.Fill(aOVDataSet.t_Klanten);
t_KlantenViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("t_KlantenViewSource")));
t_KlantenViewSource.View.MoveCurrentToFirst();
I use Entity Framework. Why doesn't those two solutions work for me. Are there any other solutions to refresh the DataGrid?
If you see the old value with that type of data binding, it means you don't update the initial source, but only the temporary one (in your case t_KlantenViewSource). Calling Refresh method on the data added by FindResource cause app to reload it from pre-compiled resource, which won't change in this case.
In other words, the problem is you use pre-compiled resource
On the same time, you fill the dataset with actual data, but your dataset is in memory, view source - inside application file.
You can try:
binding ItemsSource of the entire datagrid or separate column to the TableAdapter dataset
change resource compiling behaviour to Content, thus the app will reload it from external file each time you call Refresh method.
ADDITION:
You can find a solution for your case, just to save time. Check paragraph "performing updates" Other way is to provide NotifyPropertyChanged Event for each bound parameter, but I can't say it is better in this case, assuming you update columns via unique buttons.
To be short, you need a method like this on your button clicked / property changed:
aOVDataSett_KlantenTableAdapter.Update(aOVDataSet.t_Klanten)
after button click first set datagrid datasource to null then assign the datas
datagrid.datasource=null
Thank you all for your answers. As Jasmine suggested, I reloaded the dataset and rebounded the datagrid. Maybe it's not the best way to do it but it was the only solution I had then.

Most efficient way to retrieve/update an object from a collection?

I'm working with a silverlight datagrid that is bound to an observable collection of a business object.
We do not support inline editing of the objects within the grid but we do display a corresponding editing panel for the user selected row.
When the user submits the edits from this panel, I'm persisting the changes in the DB but I'd like the changes to also reflect in the grid.
I know that through the use of the observable collection and notify property changed that if I change the object that the selected row is bound to, the changes will display in the grid.
However, since I'm not inline editing, I need to search the observable collection for the object and make the change to the business object's instance in the observable collection.
I'd like to avoid having to loop through the collection to find said object but I'm worried this is the only real way.
There's no other more efficient, less performance-heavy way that I'm not aware of to retrieve an object from a collection correct? Other than simply to loop through until I hit it?
can you bind your edit grid to the selected item of the display grid? Since they are references this will push/pull changes into the observable collection which can then be persisted.
after having some critical exceptions happen that i couldn't keep track of i decided to avoid the databinding to the edit panel and go with Jeffrey L Whitledge's suggestion.
i'm maintaining a reference to the object displayed in the panel and with the notify changed, when i the user submits the update panel and i persist the changes to the business objects, i'm setting the changes to the grid row object that's bound.
thx guys

How to implement CRUD Master Details on the same screen under MVVM

I have a MVVM (Prism) application that I need to implement a master details screen wheer the master is a listview and the details is displayed next to it. Read-only seems easy enough (haven't done it yet but I've got my head around WPF binding) but edit/add confuses me.
How to I make it so the master is not updated until the details is saved?
How do I make it so you can't change the master's current selection while in edit/add mode?
I've been googling a plenty but have not found any meaty examples of this.
Thanks.
PS: This view is a child view on a larger screen. This is why I want both master and detail together.
You certainly can do this, though in my opinion such a UI design fails to harness the full power of WPF. Old WinForms UIs usually didn't update most of the application until data was saved to SQL Server (or wherever) because they didn't have real business objects and a powerful binding system like WPF. Trying to copy WinForms limitations within WPF seems like a step backward to me. Why not show the latest data everywhere it is visible in the UI, including in the master view? Also, why not allow the user to edit multiple items before saving, for example marking any edited but unsaved item with an animated marker in the master view? Combine these with a generalized undo and you have a better design and more intuitive for the user.
However if your business requirements make it absolutely necessary, here is how to do it:
Preventing changes to data from being visible outside the detail until it is saved
Upon entry into your "edit/add mode", make a copy of the data objects and set your detail view's DataContext to the copy instead of the live object. When the data is "saved", copy the data from the shadow copy back into the live object and set your detail view's DataContext back where it should be.
Preventing the master's current selection from changing while in edit/add mode
Two possibilities:
During edit/add mode, change the master view to disallow mouse hit testing or keyboard focus
When edit/add mode begins, capture the "current selection" then add an event handler that watches for "current selection" changes and immediately changes the selection back to what it was. When edit/add mode ends, remove the handler. This handler can be conveniently coded using a lambda expression and using a closure on a local variable to store the current selection.
Thanks for the answer. Now I've re-read my message, I see it is rather vague. I have a screen that edits an object which contains multiple lists of other child objects. I've implemented these as different tabs in a tab control. One of these tabs edits the comments, so I wanted to display a list of comments with an edit panel for the current selection next to the list. The user could then use add, edit or delete buttons to update the list. I wanted to do this in a pure(ish) MVVM way.
I came up with the following design which seems to work with minimal hacks.
The View includes a list of the child objects simply as a ListView bound to an observable collection within the ViewModel. I included a child object buffer – this is used to buffer changes until they are ready to be saved back to the list (or thrown away).
The View also includes an edit panel bound to the buffer object in the ViewModel. The buffer is updated whenever the list view’s current selection changes using a deep copy. I tried using data binding on the Selecteditem property but the set was never called, so a small code-behind method was added to force the property to be updated when the selection was changed.
The list view and edit view are mutually exclusive. In theory you could hide the disabled one, perhaps using a flip screen. As a general pattern, it is better for my app to have both visible at the same time as the edit panel may show extra information not shown in the list view. The choice as to which panel is enabled is controlled by binding IsEnabled to a ViewModel property like IsEditCommentMode.
Commands to manage the list have to be added, these are New, Editand Delete. Note that Add and Edit will set set up the buffer then set IsEditCommentMode to true. These list management commands are only available when IsEditCommentMode is false.
The edit panel implements Save and Cancel commands, they are only be enabled when IsEditCommentMode is true. When Save is executed, it should copy from the buffer to the list (either add or update) and fire the change notification. Finally, it should set IsEditCommentMode to false.
This all works well and does not seem to violate any MVVM tenents (in my humble but often flawed opinion).

Categories

Resources