Binding ListBos ItemSource to Combobox's selectedVAlue - wpf

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>

Related

DatagridTemplateColumn Checkbox binding searching for property on viewmodel

In the following snippet, I have a binding that is searching for "Checked" on the viewmodel. But it is not in my ViewModel, it is on items in my DataGrid ItemsSource.
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Center">
<CheckBox IsChecked="{Binding Checked, UpdateSourceTrigger=PropertyChanged}" />
</ContentControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
How do I make the binding use the items in ItemsSource?
I've searched high and low but can't find the problem...
Edit: DataGrid binding:
<DataGrid MaxHeight="250" VerticalScrollBarVisibility="Auto" ItemsSource="{Binding Questions}" CanUserAddRows="False" AutoGenerateColumns="False" Width="Auto">
<DataGrid.Columns>
<DataGridTemplateColumn ..... etc.. above snippet here
...
</DataGridTemplateColumn.....
</DataGrid.Columns>
</DataGrid>
ViewModel:
public class Question
{
public bool Checked { get; set; }
public string Text { get; set; }
/// <summary>
/// Answers to show if the Question is checked
/// </summary>
public List<Answer> Answers { get; set; }
}
public class MyViewModel : ViewModelBase
{
private readonly IEnumerable<Question> _Questions;
/// <summary>
/// Questions for Definition of Done
/// </summary>
public IEnumerable<Question> Questions
{
get
{
return _Questions;
}
}
}
Your binding should work provided that the Checked property actually belongs to the type T of the IEnumerable<T> that you have set or bound the ItemsSource property of the DataGrid to. Make sure that the name of the source property is "Checked" and that it has a public getter and setter.
If the Checked property belongs to the view model you could use a RelativeSource to bind to it:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Center">
<CheckBox IsChecked="{Binding DataContext.Checked, RelativeSource={RelativeSource AncestorType=DataGrid}, UpdateSourceTrigger=PropertyChanged}" />
</ContentControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Wpf Combobox with databinding: initial value is empty

In the following xaml fragment SessoList is a list of string ("M" and "F").
<ComboBox IsEditable="False" Margin="5" SelectedValue="{Binding Sesso}" ItemsSource="{Binding SessoList}" Width="40" Height="28"/>
The combobox works as expected and it is pre-populated reflecting the value of Sesso in the viewmodel.
The combobox selectable items are only two and fixed so I tried to simplify defining them in xaml:
<ComboBox IsEditable="False" Margin="5" SelectedValue="{Binding Sesso}" SelectedValuePath="{Binding Tag}" Width="40" Height="28" Name="Primo">
<ComboBoxItem Content="M" Tag="M" />
<ComboBoxItem Content="F" Tag="F" />
</ComboBox>
This combobox is capable of updating the viewmodel property sesso, but is not pre-populated with the correct value.
The following error is reported:
BindingExpression path error: 'Tag' property not found on 'object'
How can I successfully define the combobox items in xaml and have it display the right value based on SelectedValue databinding ?
Forgot to mention I'm using .Net 4.0
As I can understand, you want to define the ComboBox ItemsSource in XAML,
here is the solution that worked for me:
Xaml Window resources:
<Window.Resources>
<x:Array x:Key="Array" Type="{x:Type nirHelpingOvalButton:ComboObjectModel}">
<nirHelpingOvalButton:ComboObjectModel Content="M_Content" Tag="M_Tag"/>
<nirHelpingOvalButton:ComboObjectModel Content="F_Content" Tag="F_Tag"/>
</x:Array>
Xaml Combo:
<Grid>
<ComboBox IsSynchronizedWithCurrentItem="True" IsEditable="False" SelectedIndex="0" Margin="5" ItemsSource="{StaticResource Array}"
SelectedValue="{Binding Content, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
SelectedValuePath="Tag" Width="90" Height="28" Name="Primo">
<i:Interaction.Behaviors>
<nirHelpingOvalButton:CustomComboSelectionBehavior/>
</i:Interaction.Behaviors>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Content}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox></Grid>
View model combo SelectedValue binded property:
public string Content
{
get { return _content; }
set
{
_content = value;
OnPropertyChanged("Content");
}
}
List item Behavior Code:
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
var firstItem = AssociatedObject.ItemsSource.Cast<object>().FirstOrDefault();
AssociatedObject.SelectedItem = firstItem;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Loaded -= OnLoaded;
}
regards

ComboBox in my WPF DataGrid won't display any items

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"}});
}
}
}

SelectedItem for combobox is always null

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>

ObservableCollection Images in Listbox to Content Control master detail WPf

I have an observablecollection of Images that get populated via the following code:
<StackPanel Orientation="Horizontal" Grid.Column="0">
<ListBox ItemsSource="{Binding BigImageView}" IsSynchronizedWithCurrentItem="True"
SelectedIndex="0" SelectedItem="{Binding CurrentItem}" />
</StackPanel>
<ContentControl Name="Detail" Content="{Binding BigImageView, Mode=OneWay}"
Margin="9,0,0,0" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top"/>
However the Content Control is supposed to bind to the BigImageView via an ObservableCollection
BigImage = new ObservableCollection<Image>();
_listView = CollectionViewSource.GetDefaultView(BigImage);
_listView.CurrentChanged += new EventHandler(OnCurrentChanged);
public System.ComponentModel.ICollectionView BigImageView
{
get
{
return _listView;
}
set
{
_listView = value;
OnPropertyChanged("BigImageView");
}
}
I want to return the image to the content control when I move the listbox. I have been racking my brain and trying everyhitn but it does not work. any help would be appreciated.
There is no need to bind the selecteditem, the collectionview should take care of that.
Try this:
<ListBox ItemsSource="{Binding BigImageView}" IsSynchronizedWithCurrentItem="True" />
<ContentControl Name="Detail" Content="{Binding BigImageView, Mode=OneWay}" VerticalAlignment="Top">
<ContentControl.ContentTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
<ContentControl.ContentTemplate>
1
Create a viewmodel with a list and a selected item:
public class BigImageViewModel : INotifyPropertyChanged
{
private string bigImage;
//string for path?
public ObservableCollection<string> BigImageView {get; set; } //Of course, make sure it has a value
public string SelectedBigImage
{
get { return bigImage; }
set { bigImage = values; NotifyPropertyChanged("SelectedBigImage"); }
}
}
Set this object on the DataContext of your control in the constructor:
DataContext = new BigImage(); //Make sure you initialize your list
Set the ListBox ItemsSource to your BigImage list, bind your SelectedItem to BigImageView
and use that in your content control:
<ListBox ItemsSource="{Binding BigImageView}" SelectedItem={Binding SelectedBigImage} />
ContentControl:
<ContentControl Name="Detail" Content="{Binding SelectedBigImage, Mode=OneWay}" VerticalAlignment="Top">
<ContentControl.ContentTemplate>
<DataTemplate>
<Image Source="{Binding}"/> <!-- Nice template for showing your string BigImage -->
</DataTemplate>
<ContentControl.ContentTemplate>
</ContentControl>
2
Or screw that view model:
Set the list directly in the constructor (after the InitializeComponent() ):
myListBox.ItemsSource = ObservableCollection<string>(); //Make sure you initialize your list with whatever your object is..
Give the list a name:
And bind with an ElementName binding to your selected item:
<ContentControl Name="Detail" Content="{Binding ElementName=myListBox, Path=SelectedItem}" VerticalAlignment="Top">
<ContentControl.ContentTemplate>
<DataTemplate>
<Image Source="{Binding}"/> <!-- Nice template for showing your string BigImage -->
</DataTemplate>
<ContentControl.ContentTemplate>
</ContentControl>

Resources