I'm working on Silverlight 4, and I have difficulties to make my combobox work correctly.
On changing selected items, selectedItem value stays null. I defined combobox as following:
<ComboBox
x:Name="ProductGroupCombobox"
Grid.Row="2"
Margin="10,15"
Height="30" Width="200"
Background="{x:Null}"
BorderBrush="{x:Null}"
ItemsSource="{Binding}"
SelectionChanged="ProductGroupCombobox_SelectionChanged"
SelectedItem="{Binding Path=ProductType, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
<ComboBox.ItemTemplate>
</ComboBox>
Does anyone have idea?
Your SelectedItem property needs to be bound to an instance in your collection, whereas it appears you have your DataContext set to what I am assuming is a collection. Note how I adjusted the binding to be that of the collection and a separate property to be that of an instance within the collection.
public class MyData : INotifyPropertyChanged
{
List<String> ProductTypes {get; set;}
String _selectedProductType = String.Empty;
String SelectedProductType
{
get
{
return _selectedProductType;
}
set
{
_selectedProductType = value;
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs("SelectedProductType");
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
...
this.DataContext = new MyData();
...
<ComboBox
x:Name="ProductGroupCombobox"
Grid.Row="2"
Margin="10,15"
Height="30" Width="200"
Background="{x:Null}"
BorderBrush="{x:Null}"
ItemsSource="{Binding ProductTypes}"
SelectionChanged="ProductGroupCombobox_SelectionChanged"
SelectedItem="{Binding Path=SelectedProductType, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Related
Please let me know how to assign value to combobox with following code, as assign the Display text
`<ComboBox x:Name="ComboBox" HorizontalAlignment="Left" Margin="256,41,0,-6"
VerticalAlignment="Top" Width="108" Height="26" FontSize="13" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>`
You can simply use DisplayMemberPath property to set the name of the column of your DataTable which will be displayed.
Code behind:
ComboBox.ItemsSource = dt.AsDataView();
XAML:
<ComboBox x:Name="ComboBox" DisplayMemberPath="Name" HorizontalAlignment="Left" Margin="256,41,0,-6"
VerticalAlignment="Top" Width="108" Height="26" FontSize="13">
</ComboBox>
You have to create a list of strings called Name in your viewModel that implements INotifyPropertyChanged
XAML:
<ComboBox x:Name="ComboBox" ItemsSource="{Binding myListofItems}" HorizontalAlignment="Left" Margin="256,41,0,-6" VerticalAlignment="Top" Width="108" Height="26" FontSize="13" />
C#:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private List<string> _myListOfItems = new List<string> ();
public List<string> myListOfItems
{
get { return (_myListOfItems); }
set
{
_myListOfItems = value;
OnPropertyChanged ("myListOfItems");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) {
handler (this, new PropertyChangedEventArgs (propertyName));
}
}
public MainWindow()
{
InitializeComponent ();
this.DataContext = this;
// Start Populating your List here
// Example:
for (int i = 0; i < 10; i++) {
myListOfItems.Add (i.ToString ());
}
}
}
<ComboBox x:Name="cmbSubLocation"
DisplayMemberPath="SubLocationName" SelectedValuePath="Id"
VerticalAlignment="Top" Width="108" Height="26" FontSize="13" >
</ComboBox>
I have a ComboBox which is Binded to a List<String> defined in the ViewModel.
I have as well a ListBox who's ItemSource depends on SelectedValue from the ComboBox.
In the ViewModel, I have the following properties:
List<String> ComboBoxSource
string SelectedValue (ComboBox selected value)
ObservableCollection<String> ListBoxSource
Now, when the ComboBox selectedvalue changes, I am setting the SelectedVAlue property in the ViewModel(DataContext) explicitly which is raising a PropertyChange Event on ListBoxSource in order to update the ListBox.
My question is how can I do this without explicitly setting SelectedVAlue in ViewModel i.e Can I bind the ComboBox.SelectedVAlue to my SelectedVAlue property ?
Here is my XAML:
<ComboBox Grid.Column="0" Grid.Row="0" x:Name="ComboBoxVersions" SelectedIndex="0" Margin="10" SelectionChanged="ComboBoxVersions_OnSelectionChanged" ItemsSource="{Binding EnvironmentVersions}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Version " />
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ListBox x:Name="ListBoxEnvironments" Grid.Column="0" Grid.Row="1" Height="300" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" Margin="10" SelectionMode="Multiple" ItemsSource="{Binding Environments}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="800" >
</WrapPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox x:Name="CheckBoxEnvironment" Content="{Binding}" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Margin="5">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here is the Code Behind:
/// <summary>
/// Handles the OnSelectionChanged event of the ComboBoxVersions control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="SelectionChangedEventArgs"/> instance containing the event data.</param>
private void ComboBoxVersions_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var dataContext = this.DataContext as TestRunnerControlViewModel;
dataContext.SelectedVersion = ((ComboBox) sender).SelectedValue.ToString();
}
Use SelectedItem instead of SelectedValue because it is more appropriate to bind, just create a SelectedVersion property, bind this property to the combobox's SelectedItem, whenever the SelectedItem is changed, update you ListBox itemSource in the setter of that property.
INotifyPropertyChanged interface is necessary to let the ListBox know that their source has been changed
private List<String> _environmentVersions;
public List<String> EnvironmentVersions
{
get
{
return _environmentVersions;
}
set
{
if (_environmentVersions == value)
{
return;
}
_environmentVersions = value;
OnPropertyChanged();
}
}
private ObservableCollection<String> _environments ;
public ObservableCollection<String> Environments
{
get
{
return _environments;
}
set
{
if (_environments == value)
{
return;
}
_environments = value;
OnPropertyChanged();
}
}
private String _selectedVersion ;
public String SelectedVersion
{
get
{
return _selectedVersion;
}
set
{
if (_selectedVersion == value)
{
return;
}
_selectedVersion = value;
//update your listBox itemSource
// ...
}
}
and in the Xaml:
<ComboBox Grid.Column="0" Grid.Row="0" x:Name="ComboBoxVersions" SelectedIndex="0" Margin="10" SelectedItem="{Binding SelectedVersion}" ItemsSource="{Binding EnvironmentVersions}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Version " />
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I'm completely new to WPF so please apologise any "stupid" mistakes.
I have a datagrid with only one column, that is a combobox. The datagrid shows a new empty line as expected. But if I select a value in the combobox on the new line, no additional new row is added. I already tried to add an edit template according to this answer: datagrid showing one new row, but not any subsequent but that did no help.
<Window x:Class="WPFSpielplatz.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="clr-namespace:WPFSpielplatz"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<d:MainWindowViewModel />
</Window.DataContext>
<Grid>
<StackPanel HorizontalAlignment="Left" Height="319" VerticalAlignment="Top" Width="517">
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding GroceryItems}" CanUserAddRows="True">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Combo">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=DataContext.GroceryItemTypes}" SelectedItem="{Binding GroceryItemType, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Name" ></ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=DataContext.GroceryItemTypes}" SelectedItem="{Binding GroceryItemType, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Name" ></ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Grid>
My ViewModel:
using System.Collections.ObjectModel;
using System.ComponentModel;
using WPFSpielplatz.Annotations;
namespace WPFSpielplatz
{
public class MainWindowViewModel:INotifyPropertyChanged
{
private ObservableCollection<GroceryItem> _groceryItems;
public MainWindowViewModel()
{
GroceryItemTypes = new ObservableCollection<GroceryItemType>
{
new GroceryItemType("Food"),
new GroceryItemType("Non-Food")
};
_groceryItems=new ObservableCollection<GroceryItem>
{
new GroceryItem(){GroceryItemType=GroceryItemTypes[0]},
new GroceryItem(){GroceryItemType=GroceryItemTypes[1]}
};
}
public ObservableCollection<GroceryItem> GroceryItems
{
get { return _groceryItems; }
set
{
_groceryItems = value;
OnPropertyChanged("GroceryItems");
}
}
public ObservableCollection<GroceryItemType> GroceryItemTypes { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The "domain" classes:
GroceryItem:
namespace WPFSpielplatz
{
public class GroceryItem
{
public GroceryItemType GroceryItemType { get; set; }
public GroceryItem()
{
}
}
}
GroceryItemType:
namespace WPFSpielplatz
{
public class GroceryItemType
{
public GroceryItemType()
{
}
public GroceryItemType(string name)
{
Name = name;
}
public string Name { get; set; }
}
}
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding GroceryItems}"/>
is simply enough for binding your collection to the DataGrid. It is already relative, however you just need to bind your properties of the GroceryItem class to your DataGrid as follows:
<ComboBox ItemsSource="{Binding GroceryItemType.Name, Mode=TwoWay"}/>
This will insert the name for every GroceryItemType to the associated GroceryItem in a ComboBox. You will probably end up in having just the name of the GroceryItemType in the ComboBox since you did specify this as your ItemsSource. I don't think that is what you want but for now, I don't see any more code in order to understand, what you want to archive.
Please note that you will have to implement INotifyPropertyChanged in both Models (GroceryItem and GroceryItemType) if you want to reflect the changes to the ViewModel and vice versa. This is where the Mode=TwoWay comes in handy.
Ok, I solved it. It worked all the time, the problem was, that my <DataGridTemplateColumn.CellTemplate> and my <DataGridTemplateColumn.CellEditingTemplate> looked the same so I could change values in the combobox without ever entering editing mode. But only after entering and successfully leaving editing mode a new row is added to the datagrid.
To get this working you have to click multiple times in the cell you want to edit and then tab out of it for the new row to be added.
So the updated code for the View looks like this:
<Window x:Class="WPFSpielplatz.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="clr-namespace:WPFSpielplatz"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<d:MainWindowViewModel />
</Window.DataContext>
<Grid>
<StackPanel HorizontalAlignment="Left" Height="319" VerticalAlignment="Top" Width="517">
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding GroceryItems}" CanUserAddRows="True">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Combo">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=GroceryItemType.Name}" ></TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel>
<TextBlock>Edit</TextBlock>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=DataContext.GroceryItemTypes}" SelectedItem="{Binding GroceryItemType, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Name" ></ComboBox>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Grid>
I have a WPF user control that contains a DataGrid. This DG contains several columns including a ComboBox for states. The list of states is populated and stored as a property in my ViewModel.
I am trying to bind the StateList Property to the ItemsSource of my Combobox but when I run the form and try to edit the DG, the combobox does not contain any values, the combobox is empty.
Here is the XAML for the usercontrol.
<UserControl x:Class="myproject.View.ucContactView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignHeight="475" d:DesignWidth="977">
<UserControl.Resources>
<ResourceDictionary Source="/Templates/MyResourceDictionary.xaml"/>
</UserControl.Resources>
<Grid DataContext="{Binding ViewModel}">
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding AddressCollectionViewSource.View}">
<DataGridTemplateColumn Header="State" Width="160">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding StateDescription}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox Name="cboState"
SelectedValuePath="StateKey"
ItemTemplate="{StaticResource dtStateTemplate}"
ItemsSource="{Binding StateList}"
SelectedItem="{Binding StateKey, Mode=TwoWay}"
Width="100" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid>
</Grid>
</UserControl>
The odd thing is that if I create another combobox on this usercontrol with the exact same combobox, this combobox works as expected.
<!-- this works as long as it's not in the DG -->
<StackPanel Height="126" HorizontalAlignment="Left" Margin="766,275,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="200" >
<ComboBox Name="cboState2"
SelectedValuePath="StateKey"
ItemTemplate="{StaticResource dtStateTemplate}"
ItemsSource="{Binding StateList}"
SelectedItem="{Binding StateKey, Mode=TwoWay}"
Width="100" />
</StackPanel>
Why won't the combobox in the DG display the values from the StateList property? Any why does the separate combobox work properly?
It's not working because your ComboBox is looking for StateList as a property of the DataContext of the DataGrid. That is, it's trying to bind to ViewModel.AddressCollectionViewSource.View.StateList when it needs to be binding to ViewModel.StateList. Check your output window while debugging and I bet you'll see a binding error to the effect of Could not find property StateList on object AddressCollectionViewSource (or maybe ICollection).
Try this instead:
<ComboBox Name="cboState2"
SelectedValuePath="StateKey"
ItemTemplate="{StaticResource dtStateTemplate}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}, Path=DataContext.StateList}"
SelectedItem="{Binding StateKey, Mode=TwoWay}"
Width="100" />
if your viewmodel is a property at the window you can do this
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ViewModel.StateList, Mode=OneWay}"
<Window x:Class="WpfStackOverflowSpielWiese.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2"
Height="300"
Width="300"
x:Name="window">
<Grid DataContext="{Binding ElementName=window, Path=ViewModel}">
<DataGrid x:Name="grid"
AutoGenerateColumns="False"
ItemsSource="{Binding AddressCollectionViewSource, Mode=OneWay}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="State"
Width="160">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding StateKey}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox Name="cboState"
SelectedValuePath="StateKey"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ViewModel.StateList, Mode=OneWay}"
SelectedItem="{Binding StateKey, Mode=TwoWay}"
Width="100" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
using System.Collections.ObjectModel;
using System.Windows;
namespace WpfStackOverflowSpielWiese
{
/// <summary>
/// Interaction logic for Window2.xaml
/// </summary>
public partial class Window2 : Window
{
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(ViewModelClass), typeof(Window2), new PropertyMetadata(default(ViewModelClass)));
public ViewModelClass ViewModel {
get { return (ViewModelClass)this.GetValue(ViewModelProperty); }
set { this.SetValue(ViewModelProperty, value); }
}
public Window2() {
this.InitializeComponent();
this.grid.Items.Clear();
this.ViewModel = new ViewModelClass();
}
}
public class StateClass : DependencyObject
{
public static readonly DependencyProperty StateKeyProperty =
DependencyProperty.Register("StateKey", typeof(string), typeof(ViewModelClass), new PropertyMetadata(default(string)));
public string StateKey {
get { return (string)this.GetValue(StateKeyProperty); }
set { this.SetValue(StateKeyProperty, value); }
}
public static readonly DependencyProperty StateProperty =
DependencyProperty.Register("State", typeof(string), typeof(StateClass), new PropertyMetadata(default(string)));
public string State {
get { return (string)this.GetValue(StateProperty); }
set { this.SetValue(StateProperty, value); }
}
}
public class ViewModelClass : DependencyObject
{
public static readonly DependencyProperty StateListProperty =
DependencyProperty.Register("StateList", typeof(ObservableCollection<string>), typeof(ViewModelClass), new PropertyMetadata(default(ObservableCollection<string>)));
public static readonly DependencyProperty AddressCollectionViewSourceProperty =
DependencyProperty.Register("AddressCollectionViewSource", typeof(ObservableCollection<StateClass>), typeof(ViewModelClass), new PropertyMetadata(default(ObservableCollection<StateClass>)));
public ObservableCollection<StateClass> AddressCollectionViewSource {
get { return (ObservableCollection<StateClass>)this.GetValue(AddressCollectionViewSourceProperty); }
set { this.SetValue(AddressCollectionViewSourceProperty, value); }
}
public ObservableCollection<string> StateList {
get { return (ObservableCollection<string>)this.GetValue(StateListProperty); }
set { this.SetValue(StateListProperty, value); }
}
public ViewModelClass() {
this.StateList = new ObservableCollection<string>(new[] {"one", "two"});
this.AddressCollectionViewSource = new ObservableCollection<StateClass>(new[] {new StateClass {State = "state", StateKey = "one"}});
}
}
}
I am trying to declaratively bind a ComboBox within a DataGrid CellEditingTemplate using a ViewModel. The ComboBox is not being bound. What am I doing wrong?
XAML:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
xmlns:data="clr-namespace:SilverlightApplication1"
mc:Ignorable="d"
x:Class="SilverlightApplication1.EmployeeDetail"
Width="640" Height="480">
<UserControl.Resources>
<data:EmployeeDetailsViewModel
x:Key="ViewModel"
d:IsDataSource="True" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource ViewModel}}" Background="White">
<sdk:DataGrid ItemsSource="{Binding Employees,Mode=TwoWay}" AutoGenerateColumns="False" CanUserSortColumns="True" CanUserReorderColumns="True" CanUserResizeColumns="True" GridLinesVisibility="All" Height="317" HorizontalAlignment="Left" Margin="12,136,0,0" Name="EmployeesGrid" VerticalAlignment="Top" Width="605">
<sdk:DataGrid.Columns>
<!-- snipped from brevity -->
<sdk:DataGridTemplateColumn Header="Status">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding EmployeeStatus.Description}" TextWrapping="Wrap"></TextBlock>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=EmployeeStatuses}" SelectedItem="{Binding EmployeeStatus, Mode=TwoWay}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
<TextBlock x:Name="SearchLabel" HorizontalAlignment="Left" Margin="12,95,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="106" Height="34"><Run FontWeight="Bold" Text="Search By Name: "/><Run FontSize="9.333" Text="(Last, First)"/></TextBlock>
<TextBox x:Name="SearchParam" HorizontalAlignment="Left" Margin="144,101,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="162"/>
<Button x:Name="SearchButton" Content="Search" HorizontalAlignment="Right" Margin="0,102,242,0" VerticalAlignment="Top" Width="75" Click="SearchButton_Click"/>
</Grid>
</UserControl>
VIEW MODEL:
using System.Collections.ObjectModel;
using SilverlightApplication1.EmployeeService;
using SilverlightApplication1.ViewModels;
namespace SilverlightApplication1
{
public class EmployeeDetailsViewModel : ViewModelBase
{
readonly IEmployeeServiceAgent _serviceAgent;
ObservableCollection<EmployeeStatus> _employeeStatuses { get; set; }
ObservableCollection<Employee> _employees { get; set; }
public EmployeeDetailsViewModel() : this(new EmployeeServiceAgent()) { }
public EmployeeDetailsViewModel(IEmployeeServiceAgent serviceAgent)
{
if (!IsDesignTime)
{
_serviceAgent = serviceAgent;
GetAllEmployees();
GetEmployeeStatuses();
}
}
public ObservableCollection<Employee> Employees
{
get { return _employees; }
set
{
if(_employees!=value)
{
_employees = value;
OnNotifyPropertyChanged("Employees");
}
}
}
public ObservableCollection<EmployeeStatus> EmployeeStatuses
{
get { return _employeeStatuses; }
set
{
if (_employeeStatuses != value)
{
_employeeStatuses = value;
OnNotifyPropertyChanged("EmployeeStatuses");
}
}
}
private void GetAllEmployees()
{
_serviceAgent.GetAll((s, e) => Employees = e.Result);
}
private void GetEmployeeStatuses()
{
_serviceAgent.GetEmployeeStatuses((s, e) => EmployeeStatuses = e.Result);
}
}
}
Update:
This seems wrong but I figured out how to get the binding working by re-referencing the ViewModel in the ItemSource Binding:
<ComboBox ItemsSource="{Binding Source={StaticResource ViewModel},Path=EmployeeStatuses}"
DisplayMemberPath="Description"
SelectedItem="{Binding EmployeeStatus, Mode=TwoWay}" />
However, a am now experiencing a problem where the SelectedItem is not bound! What am I doing wrong?
The problem is a common one that people run into. When you're in the data template of the column, you're no longer bound the the view model. At that point your data context is the EmployeeStatus object (which doesn't have an EmployeeStatuses property to bind to).
So to get the combobox binding to work you can use the ElementName=LayoutRoot to bind back up the tree to the root ViewModel.
Update: Here would be the full syntax for your binding:
{Binding DataContext.EmployeeStatuses, ElementName=LayoutRoot}
Update2: I've actually run into this as well and there is a workaround you have to implement to get the element name binding to work inside a datagrid.
If Bryant's solution does not work (in SL4), use static resources. See this link: http://blog.digitaltools.com/post/2011/05/06/Binding-a-Datagride28099s-ComboBox.aspx
Or, by creating the static resource in xaml: http://forums.silverlight.net/post/370135.aspx