WPF DataContext issue with datacontext object - wpf

I have created a simple sample with datacontext. Please get the sample from here : source I understand that the uses of DataContext is
If the user change any content in UI, it should be updated in the back end datacontext class without any additional work.
If we make any change in back end datacontext object, it should be updated in UI without any additional work.
In my sample,
If I click "click" button, the textbox value gets updated. - pass
If I click "update" button, the textbox value gets updated. - pass
If I click "clear" button, the textbox value not updated. - fail
After clicked "clear" button, If "click" or "update" button is clicked the textbox value not updated. - fail
Am I doing anything wrong? If yes, how can I initialize some value in the textbox in constructor, and after that if the user make changes, the datacontext object values need to be updated. If I update any value in code behind, the values need to updated in UI. Also if I click "clear" button all the textbox values need to be cleared. After that if user enter value again, the object need to update. How can I achieve it? Please help.
Note: In my sample I have commented some lines. In that i have casted the datacontext to the model class every time and changed it. Its working fine. Do i need to use that method to update values run time. Changing values in object will not update in UI?

The problem is that you consider the variable 'dc' linked to the DataContext, but that is not the case. To fix your code simply set the DataContext again after you change the 'dc' variable.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
dc = new Journal();
myPanel.DataContext = dc;
//myPanel.DataContext = new Journal();
}

Related

Event to fire after a System Windows Form element has been updated

I have a Windows form with a series of list boxes
The contents of subsequent lists change based on choices in earlier ones
All the boxes are bound to a BindingList with OnListChanged enabled
I use this to retain user-specified 'checked' items when elements are added or removed
However, I note that if I add an item to the list, it appears to update the UI only after all the other events have been fired
I've looked at the events I would expect to fire on the CheckedListBox, and in the related ViewModel, in order to catch the one which adds an item to the list, but so far without success
Can someone please advise me which event would allow me to call my 'CheckBoxes' method after the UI has been updated, otherwise they all get set to blank again until the form is closed and opened
private void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
// I've removed the debug statements, but this event when the bound list updates is fired before the UI updates
}
private void teams_checked_list_box_SelectedIndexChanged(object sender, EventArgs e)
{
// same with this event, and the other events like SizeChanged
}
EDITED: On reflection, I realise that the problem occurs because I am not setting the true / false checked flag in the binding, because I couldn't figure out how to do it. If someone could point me in the right direction? Code currently looks like this:
teams_checked_list_box.DataSource = Globals.ThisAddIn.TFSTeamsViewModel.ListOfTeamsFromVM.value;
teams_checked_list_box.DisplayMember = "name";
So basically I am only updating the item name, and the check flag is handled on a later pass
How are you adding items to your list? Are you re-binding the listbox? There are basically two ways you can do this depending on your method of adding items:
If you are re-binding, capture the event BEFORE the item is added. Loop through the CheckedItems property of your list box. Save the values. Add your item. Loop through the NEW values and recheck.
OR
When the user checks the item in the listbox, capture that using the ItemChecked event and then store the value of the item somewhere. (Variable, hidden textbox -- ugly, but it works -- etc.) If you are only adding items to the BOTTOM of your list, you can store the index of the item. If you are re-sorting your list, you'll need to store a unique id to reference the item. (Note: you will also need to REMOVE the checked items from your stored value if the user UN-checks an item in your listbox.) Then, after you add your items to the listbox, loop back through and set the checked value on the appropriate listbox items.

How to edit properties of a ViewModel object but only apply changes when clicking a button in the View

My screen has a list of objects of type Person, and a form that displays the person properties (name, address, weight, etc.) via databinding.
I want to be able to:
Click in a button "Edit properties", and start modifying the person's properties (I can already do that using Commands in the ViewModel);
If I click "Cancel", the edited info "rollback" to the original unmodified values of that person;
If I click "Save changes", JUST THEN the person's name changes in the person list.
My problem right now is that, as I am editing the forms, the original properties are updated, so to say, in realtime, and if I decide to cancel, I have not the original values to "go back".
I considered to Clone the selected person, but that seemed to be odd. I think a better approach would be to change only the text properties of the field, and update back only when clicking to submit changes, but I don't know how to do it, specially how to preserve databinding consistency.
When you bind, use UpdateSourceTrigger=Explicit. That will tell XAML not to update the source binding until you tell it to. Then, when your Save button is clicked, you can call UpdateSource on the binding to push the contents of your controls back to the Person object, something like:
var nameBinding = nameTextBox.GetBindingExpression( TextBox.TextProperty );
nameBinding.UpdateSource();
To cancel, use UpdateTarget instead, which will push the data in the Person object back to your control.
You can try it with this Undo/Redo approch
http://blog.notifychanged.com/2009/01/30/using-the-viewmodel-pattern-to-provide-undo-redo-in-wpf/
Or
You could have a a Current and Previous property created in View model to which is going to hold the edited values and the other will have original value. The required action of rollback can be performed be reassigning the values
There are also open-source projects available to help with this, including http://undo.codeplex.com/

WPF, MVVM and combobox

I am having some trouble with my comboBox logic in my viewModel. The viewModel populates the comboBox and the user can select items.
When an item is selected, some editable info appears in the view and they can make changes. Now, I want to prompt the user to save if changes were made and not saved and they are trying to select another item in the drop down (a "Save?" yes/no/cancel messageBox).
Right now I need to remember the previously selected item and handle this myself by resetting the selected item if the user selects cancel. Since the comboBox does not have a PreviewSelectionChanged event, this is the only way I can think of of handling this scenario. It works but it gets a little messy hwen there are multiple comboBoxes, etc.
Am I missing anything or is this just the way it needs to be done?
You essentially have to make a flag in your view model called isDirty or something along those lines.
public class EditorViewModel
{
private bool _isDirty = false;
private long _editableProperty;
public long EditableProperty
{
get { return _editableProperty; }
set
{
_editableProperty = value;
// We've detected a change so mark this view model as dirty.
_isDirty = true;
}
}
}
Note that you will have to have to jump through a few more hoops if you want ensure that the data is in fact different from your original. So say someone accidently adds a space in EditableProperty and removes it your view model will think it's dirty and prompt the user.
The Windows Forms ComboBox provided a SelectionChangeCommitted event, but for the WPF ComboBox control you correct in that there is no event that will notify before the selection change occurs that will provide you with a means of cancelling the event.
If you are going to take a change tracking/editable approach, I would recommend considering implementing IChangeTracking and IEditableObject on the items in your combobox items source.
You will probably have to handle the SelectionChanged event, inspect the removed items to determine if the item that was previously selected was modified and then display a dialog requesting confirmation. If no/cancel was indicated, you can then set the selected index back to that of the previously selected item.
What about making the Editable item a copy of an item instead of the actual item?
So your ViewModel would contain
ObservableCollection<MyModel> ComboBoxItems;
int SelectedComboBoxIndex;
MyModel EditingItem;
Whenever the PropertyChange event occurs on SelectedComboBoxIndex, you check and see if EditingItem is null or not. If it is null, it means you're safe to switch and you set
EditingItem = ComboBoxItem[SelectedComboBoxIndex]).Copy();
If the EditingItem is not null, then you throw up a prompt asking if the user wants to save changes or cancel.
When the user hits Save, it takes the EditingItem and applies the changes to the data store and updates the item in the ComboBoxItems list.
If they hit Cancel, the EditingItem is simply discarded.

DevExpress XtraGrid checkbox check not registered unless focus changes

We have a databound XtraGrid on our Windows form. One of the columns is a check box. The problem is as follows: when users check the checkbox and click OK button, the checkbox, while visibly checked, is not considered checked by the grid. When I do this (while looping through rows):
isAllowed = Convert.ToBoolean(viewMain.GetRowCellValue(nRowCtr, "IsAllowed"))
I get back False. BUT, if the user checks the box, and then clicks somewhere else on the form or on another row in this grid, thus taking away focus from the checked checkbox, the same code above will return True.
Any insight on how to fix this behavior would be greatly appreciated.
Workaround found:
With default settings, when users click on a cell to edit it, the cell goes into edit mode, loads the editor control (in this case I have a CheckEdit repository control) and changes control's value (in this case checked state). If I click on another row, or another control, the cell then gets out of edit mode, committing the change to data item. But if I click on a button, then my change is lost. The workaround is to use the CheckEdit's CheckedChanged event to close editor:
Private Sub edCheck_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles edCheck.CheckedChanged
gridYears.FocusedView.CloseEditor()
End Sub
There's actually a cleaner way of doing this (it works for all RepositoryItems), detailed on the DevExpress site. The idea is to call the GridView.PostEditor method from a repository item's EditValueChanged event handler to immediately save the edited value to the grid's cell and the underlying column.
This code in the view's CellValueChanging event handler solved the problem:
private void OnCellValueChanging(object sender, CellValueChangedEventArgs e)
{
_gridView.SetFocusedRowCellValue(_gridView.FocusedColumn, e.Value);
}

Applying a DataGridViewComboBoxCell selection change immediately

When I change a value in a DataGridViewComboBoxCell the new value is not immediately applied until that cell leaves focus.
Is there a way to have the new value applied immediately?
If you handle the EditingControlShowing event on the DataGridView, you can attach an event handler to the underlying ComboBox's SelectedIndexChanged event (or SelectedValueChanged, or any other ComboBox event). It will fire immediately whenever the ComboBox value changes, and you can do whatever you want with the new value.
There's example code for this in the MSDN docs for DataGridViewComboBoxEditingControl.
DataGridView.CommitEdit Method
This might be of some use to you as well. Handle the CurrentCellDirtyStateChanged event, check for Dirty, and Commit the edit. Then you can use the CurrentCell property to access the value that was selected (assuming it was validated).
DataGridView1.EndEdit()
Ignore this text, answer must be at least 30 characters

Resources