Using MVVM how can I find out if a ComboBox has changed the selected value? - wpf

I have a view that has 2 combo boxes (Call them ParentTypeCombo and ChildTypeCombo). Both of these combo boxes have the same backing drop down list (call it WorkItemTypes).
Using MVVM how can I know when the value was changed for these combo boxes? I have bound them to properties (Call them ParentType and ChildType). But as I recall, my setter will not be called by WPF.
I don't want to just go off the event on the combo box because that will go in the code behind, not the View Model.
(I saw an example using an ObservableCollection. But I confess I did not understand it. I used a value called CollectionViewSource that it does not explain what is or where it is obtained.)

Just bind the SelectedItem to a property in the ViewModel for both parent and child
<ComboBox SelectedItem="{Binding ParentSelectedItem}" ... />
// VM
public WorkItemType ParentSelectedItem
{
get { return _parentSelectedItem; }
set
{
if(value != _parentSelectedItem)
{
//HERE you know it has changed value.
_parentSelectedItem = value;
RaisePropertyChanged("ParentSelectedItem");
}
}
}
Also you can have only one collection on the view model and bind them to both combo boxes.

Set the ComboBox IsSyncronyzedWithCurrentItem property to true, than on your vm, call this CollectionViewSource.GetDefualtView([your workitem types]), the return type is ICollectionView or something similar, and it has a current changed event.

Related

How to get the value from DataGrid's SelectedItem?

In my project i have one Datagrid and i bind the following fields that are listed below.
CustomerID, Name, Email.
I have the Entity named WS_Customer. i have put one button control for all row in datagrid.If i click the button means the i need to get the CustomerID value.
How to get it.
If i put like this means,
WS_Customer getid=(WS_Customer)DG.SelectedItem;
getidshows null..
How i got the value?
Assuming you are using MVVM... and you DataGrid is bound to a collection of the WS_Customer objects you can put a property in your view model that you can bind to the SelectedItem property of the DataGrid. Keep in mind the row must be selected for the SelectedItem property to have a value.
In xaml:
<DataGrid SelectedItem="{Binding SelectedWS_Customer}" />
In viewModel:
public WS_Customer SelectedWS_Customer
{
get
{
return _selectedWS_Customer; //private variable
}
set
{
_selectedWS_Customer = value;
}
}

How can the ViewModel request an update in the View in WPF/MVVM?

I have a dependency property on a control in my View that is bound to a field on my ViewModel. When the user clicks a menu item I want the control to update the value of that property so the ViewModel can save it in an XML file. What is the correct mechanism to have the ViewModel request that the View update that property?
Generally with MVVM controls update their bound properties (not fields) immediately as they are edited. The ViewModel is the "state", the View is just one way of seeing that state.
Your control should update the ViewModel whenever it is edited. Your ViewModel can then save it to XML when the menu command is invoked.
I had the problem that the viewmodel was not updated when clicking on a menuitem right after writing in a TextBox.
With the parameter UpdateSourceTrigger=PropertyChanged, it worked for TextBoxes:
<TextBox Grid.Column="5" Grid.Row="7" Text="{Binding SelectedPerson.Room, UpdateSourceTrigger=PropertyChanged}"></TextBox>
But unfortunately not for DatePickers...
The strange thing is that when clicking on a button instead of the menuitem, the DatePicker is updating the viewmodel.
As I don't have more time to look for a bugfix right now, I'll just change my menuitems into buttons.
Edit: the Problem is not the menuitem but the menu itself. When I move the menuitems out of the menu, it works.
Your object must implement INotifyPropertyChanged interface and your properties should look like this
private string _property;
public string Property
{
get { return _property; }
set
{
if(_property == value) return;
_property = value;
RaisePropertyChanged("Property");
}
}
so every change made to the property will be cascaded to view through the binding mechanism.
The menu item command property will be bound to a command declared in the view model and it will trigger a method on view model and set the property value. The change will be cascaded to view:
menuItem.Click -> menuItem.Command.Execute -> viewModel.method -> change the view model property -> raise property changed event -> view property changed through binding

DataContext for binding a UserControl with ViewModel within DataTemplate

What I'm trying to achieve is:
Have a ListView bound to an ObservableCollection of ItemRecords.
Have a TabControl that contains detailed view for all the ItemRecords in the ListView that were selected for editing.
Each TabItem contains a UserControl ("ItemInfo") that uses ItemInfoViewModel as its VM (and, not so coincidentally, DataContext).
ItemInfo UserControl needs to be populated with the data from the corresponding ItemRecord.
To achieve that, I'm trying to pass the ItemRecord (selected in the ListView) to ItemInfoViewModel.
Finally, the question: what do you think would be the best way to do this, without breaking the MVVM pattern?
The not-so-elegant way that I see (and it actually doesn't exactly follow the MVVM principles) is to have a DependencyProperty ItemRecord defined in the UserControl, provide its value via binding, and in the constructor (in the UserControl's code-behind) pass the ItemRecord to the VM (which we get by casting the DataContext).
The other problem is with how to actually pass the ItemRecord via binding.
Once I set the VM as the UserControl's DataContext, I cannot just use {Binding} to specify the current item in TabControl's source collection.
At the moment I am binding to the TabControl's SelectedItem using ElementName - but this doesn't sound too robust :-(
<localControls:TabControl.ContentTemplate>
<DataTemplate>
<ScrollViewer>
<localControls:ItemInfo ItemRecord="{Binding ElementName=Tabs, Path=SelectedItem}"/>
</ScrollViewer>
</DataTemplate>
</localControls:TabControl.ContentTemplate>
Any good advice will be greatly appreciated!
Alex
I think your problem is you're not quite understanding the MVVM pattern here; you're still looking at this as the different controls talking to each other. Where in MVVM, they should not be, each control is communicating with the view model independently of all the others. And the view model controls (and supplies) the logic which tells the controls how to behave.
So, ideally you would have something like:
public ObservableCollection<ItemRecord> ListViewRecords
{
get { ... }
set { ... }
}
public IEnumerable<ItemRecord> SelectedListViewRecords {
{
get { ... }
set { ... }
}
The ListViewRecords would be bound to the ItemsSource property of your ListView (the actual properties might vary based on the specific controls you're using, I'm used to the Telerik suite at the moment so that's where my head is). And the SelectedListViewRecords would be bound to the SelectedItems property of the ListView. Then for your TabControl you would have:
public ObservableCollection<MyTabItem> Tabs
{
get { ... }
set { ... }
}
public MyTabItem SelectedTab
{
get { ... }
set { ... }
}
Again, you would bind the Items property to the Tabs and SelectedItem to the SelectedTab on your TabControl. Now your view model contains all the logic, so in your SelectedListViewRecords you might do something like this:
public IEnumerable<ItemRecord> SelectedListViewRecords {
{
get { ... }
set
{
_selectedRecords = value;
NotifyPropertyChanged("SelectedListViewRecords");
Tabs.Clear(); // Clear the existing tabs
// Create a new tab for each newly selected record
foreach(ItemRecord record in value)
Tabs.Add(new MyTabItem(record));
}
}
So the idea here is that the controls do nothing more than send and receive property changes, they know nothing of the underlying data, logic, etc. They simply show what their bound properties tell them to show.

WPF TreeView ItemsSource not keeping values

I am using a wpf treeview and binding the ItemsSource to an IEnumerable of my ViewModel that has an IsChecked Property. I am binding a checkbox to this value with a Mode of TwoWay. I can see when I step through the program that it is setting this value properly on my ViewModel when I check the checkbox.
I then have a Menu Item that "Runs Checked". In this method I have a foreach loop that runs through the ItemsSource as IEnumerable of ViewModel looking for IsChecked = true to queue up the checked items to be run by a separate program. As such:
foreach (AccountViewModel account in tvClientList.ItemsSource as IEnumerable<AccountViewModel>)
{
if (account.IsChecked)
{
context.Queues.InsertOnSubmit(new Queue {Id = account.Id});
}
}
However, account.IsChecked is always false. Why is this?
i would check the following.
does the setter of AccountViewModel.Ischecked is called when clicking the treeview checkbox. if no - then thats the problem if yes you should look at your collection bindings.
debug your foreach and check wether the treeviewitemssource is the collection you expect.
maybe you can post your bindings, if that all no help.
ps: dont access your View controls directly if you use viewmodels/mvvm.
Just for anyone else encountering this issue. ItemsSource returns a new set of data, Items, however contains the current set of data.

Silverlight DataGrid binding issues after refreshing or setting selectedIndex=-1

I have a datagrid and a combobox on the form. The combobox is bound to the selectedItem of the datagrid.
I load things fine and if i select different rows the combobox is updated correcly.
If however I set datagrid.selectedIndex=-1 after it loads (so that the first row is not selected) the combobox binding no longer works. This is a problem.
I also have another scenario where the exact thing occurs. If i filter the datagrid, the binding to the combobox also stops working.
I am binding the datagrid to a CollectionViewSource like the following where _codes is an ObservableCollection
_ocvsCode = (CollectionViewSource)this.Resources["cvsCode"];
_ocvsCode.Source = _codes;
dataGrid1.ItemsSource = _ocvsCode.View;
I don't know why the binding to the combobox is failing after some operation on the datagrid.
The appropriate solution in this case is to bind the datagrid selecteditem to some variable, and to then bind the other controls to that variable as well. It is generally bad practice to bind UIElement properties directly to other UIElement properties. This will also make debugging the problem you seem to be having with coercing the selecteditem property to the combo-box.
I have come across the same problem, where a ComboBox is bound to a the value of the SelectedItem of a DataGrid.
The ComboBox control breaks when the data it is binding becomes null, and never recovers. I'm not sure why that is, but it seems to me to be a bug. When the DataGrid sorts a column, it first sets its SelectedItem to null, performs the sort, and then resets SelectedItem to the original value. When the SelectedItem becomes null, the ComboBox breaks.
Here's my work around:
Create a SelectedItem property on your class that is being used for the DataContext. Perform a check on the setter that prevents it from being set to null. Bind against this property with your DataGrid and ComboBox.
public YourItem SelectedItem
{
get { return _selectedItem; }
set
{
if (value == _selectedItem || value == null)
return;
_selectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}

Resources