I having trouble DataBinding a combo in XAML using the MVVM method.
I set the combo's source in the code behind like so:
AgesViewModel agesViewModel = new AgesViewModel();
comboAge.SelectedValuePath = "AgeID";
comboAge.DisplayMemberPath = "Age";
comboAge.ItemsSource = agesViewModel.GetAges();
And the XAML for the combo is:
<ComboBox x:Name="comboAge"
SelectedValue="{Binding AgeID}" />
The combo is part of a page with text controls and they all DataBind fine. The page DataContext is set to a ViewModel (carViewModel) which has a property called AgeID.
So when to combo items changed I want carViewModel.AgeID to be updated with the selected value.
Whenever I select an item from the combo nothing gets updated. What am I doing wrong??
Thanks in advance
I'm using XAML, C#4.5 and writing a windows store app in Visual Studio 2012.
If you want to follow the MVVM pattern, have the ComboBox's data also available in your carViewModel and bind to it.
In other words:
<ComboBox x:Name="comboAge" ItemsSource="{Binding MyAgeList}" SelectedValue="{Binding AgeID}" />
When changing the value in the ComboBox, this will also update the AgeID property.
Assuming AgeID is int (it can, of course, be whatever you want) then MyAgeList should be defined like this in carViewModel:
public List<int> MyAgeList {get; set;}
// Constructor
public CarViewModel()
{
MyAgeList = new AgesViewModel().GetAges();
}
Related
I got stuck on a problem. In the project I am working on I have to populate one column of ListView with cheboxes and another one with comboboxes. The following is the data model that I am using as an ObservableCollection to bind it to a listview. Works really well!
public class PointDataMainListView
{
public string CheckBoxName { get; set; }
public ObservableCollection<string> ComboBoxItems{ get; set; }
public Visibility visibility { get; set; }
}
Except I have a hard time changing the properties of the combobox itself. In particular the visibility property.
The following is the data template i am using for the combo box
<DataTemplate x:Key="ComboBoxCell">
<ComboBox x:Name="ComboBox"
ItemsSource="{Binding ComboBoxItems}"
Width="100"
Visibility="{Binding visibility}"/>
</DataTemplate>
When populating the listview for the first time or adding a new item to a listview visibility could be set no problem. When visibility inside my ObservableCollection < PointDataMainListView > is changed for the item already displayed nothing is happening.
One of the solution I was looking into is trying to itterate through a list view items to try and get a reference to the actual combobox to change it's property. That said, I believe there must be a more elegant solution to achieve the desired results. Thank you for any help.
Your class needs to implement INotifyPropertyChanged and your properties setters need to invoke the PropertyChanged method.
I'm very new to WPF. I'm trying to bind to a property a row in a DataGrid so that when the row's clicked the property is set. The ItemsSource that's bound to the DataGrid is an ObservableCollection of objects of type Field.
I've tried to bind to the SelectedItem attribute on the DataGrid, but the property is not being called. I'm using almost identical code to bind to the SelectedItem of a ComboBox and this is working fine. Is there a difference that I don't know about?
<ComboBox ItemsSource="{Binding RecordTypes}" SelectedItem="{Binding SelectedRecordType}" ...
<DataGrid ItemsSource="{Binding Fields}" SelectedItem="{Binding SelectedField}" ...
In my ViewModel:
private Field SelectedField
{
get
{
return _selectedField;
}
set
{
_selectedField = value;
}
}
(I will use auto properties later, it's just currently set up like this so that I could break when the property was set).
I'm not sure if it makes a difference, but the DataGrid is composed of 2 DataGridTextColumns and a DataGridTemplateColumn, which contains a checkbox.
Does anyone have any ideas? I'd really appreciate any suggestions.
To confirm, the reason that I want to listen to the click of a row is so that I can have the checkbox be checked whenever a row is clicked. If there's a better solution for this then please let me know.
You need to make it a two-way binding:
SelectedItem="{Binding SelectedField,Mode=TwoWay}"
That propagates changes in the view (user selects an item, SelectedItem changes) back to the viewmodel ("SelectedField" property).
Also, as #KevinDiTraglia pointed out, you need to make sure that the viewmodel property SelectedField is public, not private, otherwise the binding will not be able to access the getter/setter.
I have a View that is linked to my ViewModel using a DataTemplate, like this
<DataTemplate DataType="{x:Type ViewModels:ViewModel}">
<Views:View />
</DataTemplate>
The ViewModel holds a property ProcessOption that is of type MyEnum?, where MyEnum is a custom enumeration that has let's say 3 values: Single, Multiple and All. I am trying to bind a combobox to this property, so the approach I am following is:
ViewModel has a property of List<string> that is
public List<string> Options
{
get
{
return Enum.GetNames(typeof(MyEnum)).ToList();
}
}
to which I bind the ItemsSource property of the Combobox. Then, in addition to the ProcessOption property, the ViewModel also has an OptionName property (of string), which is intended to hold the selected option's name. The ViewModel implements INotifyPropertyChanged and both properties raise the PropertyChanged event in their setters. The binding I am using then is:
<ComboBox ItemsSource="{Binding Options}"
SelectedItem="{Binding OptionName}"
SelectedValue="{Binding ProcessOption}"/>
This works fine up to this point. Initially the combobox is empty and both properties are null, and when the user selects an option this is propagated to the ViewModel as it should.
The problem appears when I load the data from a Database, and I want to load the controls with initial values. In this case, in the ViewModel's constructor I have this:
this.ProcessOption = objectFromDB.ProcessOption // this is the value restored from DB, let's say it is MyEnum.Multiple
this.OptionName = Options.First(x => x.Equals(Enum.GetName(typeof(MyEnum), objectFromDB.ProcessOption)));
The problem is, although the above sets the two properties to their correct values, they are later set to null from the Combobox binding, so the initial values are not kept. I have also tried to do something like if (value == null) { return; } in the properties' setters, in which case they have the correct values after the View loads, however the Combobox still does not display the correct option, it is empty.
I should also note that I've also tried setting IsSynchronisedWithCurrentItem and it doesn't make any difference, apart from the fact that the first element is displayed instead of the combobox being empty.
Can anyone help with this binding? Any help will be very much appreciated, this is driving me crazy!
<ComboBox ItemsSource="{Binding Options}"
SelectedItem="{Binding OptionName}"
SelectedValue="{Binding ProcessOption}"/>
Your binding doesn't look like it should work at all -- you don't have TwoWay binding set up, and I think SelectedItem and SelectedValue is an either/or proposition.
I suggest that you get rid of OptionName and just bind SelectedItem to ProcessOption (TwoWay) with an IValueConverter that will convert to/from string.
I'm working on my first true WPF MVVM pattern application.
Currently I have a number of ComboBoxes on various screens that are bound to Collection classes and properties of the relevant ViewModel class.
They always have an entry with the text <Add>, which is really an empty object class and I currently use it to trigger an AddNewObject event if the Property bound to the SelectedItem has <Add> in its ToString() output. This strikes me as cumbersome and it ties the View too closely to the View model for my liking.
e.g.
<ComboBox ItemsSource="{Binding AllObjects}" SelectedItem="{Binding SelectedObject}" />
then in ViewModel code:
public SomeObjectType SelectedObject
{
get{return this.fieldSomeObjectType;}
set
{
if(null==value)
return;
if(value.ToString().Contains(#"<Add>"))
{
if(null!=this.AddNewObject)
{
this.AddNewObject;
}
}
}
}
Is there a way in XAML of adding this extra line into the ComboBox drop down list and binding it to an AddNewObject Command?
The code you've written in your view has nothing to do with your business logic. Its fine.
MVVM doesn't say that you shouldn't have anything in the codebehind of the view. Showing 'Add' is a requirement on the view and can be handled by the code behind of view.
In ASP.NET I've been doing this that I databinded the list control to some data but also specified some items in the html and it would merge them. Have you tried that?
use CompositeCollection for merging a default item with a itemsource. http://msdn.microsoft.com/en-us/library/ms742405.aspx
I'm using a Silverlight 4.0 project that utilizes MVVM and we have a combobox that resides on a view and has its values and selected value bound to an observable collection of Organizations and a SelectedOrganization respectively (both values exist on the viewmodel). With our project the page that this control is on can be hidden or shown. The first load everything looks great but when you go to a different control (hide the tab with the control and then go back to it) the value that is currently selected in the combo box looks like it's blank, but when I debug, the selected value is still there.
The visual tree is getting recreated, but I have no idea why the combobox loses the text that should be in the box when the parent page is hidden and then re-shown. All other controls on the page behave correctly (autocompletetextbox, textblocks, textboxes, all of which have data bound to the viewmodel the same way).
Here's how the combobox is declared:
<ComboBox
SelectedItem="{Binding SelectedOrganization, Mode=TwoWay}"
ItemsSource="{Binding Organizations}"
DisplayMemberPath="Name"
Margin="5,0"
MinWidth="100" />
the Class for the organization is here:
[DataContract]
public class Organization
{
[DataMember]
public Guid OrganizationID { get; set; }
[DataMember]
public string Name { get; set; }
}
and the viewmodel has the following code for the bindings:
public Organization SelectedOrganization
{
get { return (Organization)GetValue("SelectedOrganization"); }
set
{
SetValue("SelectedOrganization", value);
}
}
public ObservableCollection<Organization> Organizations
{
get { return (ObservableCollection<Organization>)GetValue("Organizations"); }
set { SetValue("Organizations", value); }
}
What do I need to do to keep the selected value when I switch parent pages?
The problem is that I declared the ItemsSource AFTER the SelectedItem. Apparently this is a bug in Silverlight 3 and 4. The answer was discussed here Silverlight Combobox and SelectedItem.
Just a quick note on yet a SL3 bug.
I haven't reproduced this bug in a clean environment (since I'm getting quite tiered of reproducing SL ComboBox bug's...), but I experienced an issue with roughly this setup:
ItemsSource binds to property of type List on Object X.
SelectedItem binds to property of type String on Object X.
Object X implements INotifyPropertyChanged.
SelectedItem is set after ItemsSource in XAML code as the above post instructs.
ItemsSource is set to TwoWay BindingMode.
Behaviour: When the user TAB's from a textbox into the combobox, the combobox value is 'blanked', while the ViewModel maintains its value. The value is displayed again correctly when the user TAB's out of the ComboBox. Please note that the value is not blanked, if the combobox is merely clicked, or if it tabbed to from another combobox.
Solution: When stepping through the code with a debug'er it seems that SelectedItem is returned before ItemsSource, even though ItemsSource is declared before SelectedItem in the XAML code.
The solution was to change the ItemsSource from TwoWay BindingMode to OneWay BindingMode.
Probably this prevents some events from being fiered behind the scenes.
Br. Morten
Could be helpful if adding to previous post, I noticed that my selectedItem binding property must contain a conditional that avoid assing null value, because combobox control still wants to reset value once the control is hidden by scroll or whatever.
i.e. :
public string Month{
get {return _month;}
set {
if (value==null)
return;
_month = value;
}
}
Use this
<ScrollViewer Grid.Row="6" Grid.ColumnSpan="4" Height="190">
<sdk:DataGrid Name="datagridInvestigation"
AutoGenerateColumns="False" Width="650"
MinHeight="180" >
</sdk:DataGrid>
</ScrollViewer>
instead of
<sdk:DataGrid Name="datagridInvestigation"
AutoGenerateColumns="False" Width="650"
Height="180" ScrollViewer.HorizontalScrollBarVisibility="Auto" >