I want to databind the selected item of a combobox to a c# property. When i do the following, the property get the value "Suite.Module.RateExperiment.ViewModels.ChamberViewModel"(which is not the value of the selected item in the combobox):
<ComboBox DisplayMemberPath="ChamberName" Grid.Column="0" Grid.Row="1" Height="20" VerticalAlignment="Top" ItemsSource="{Binding ChamberCollection}" SelectedValue="{Binding SelectedChamber}">
</ComboBox>
And c#:
public string SelectedChamber
{
get { return _selectedChamber; }
set
{
_selectedChamber = value;
UpdateChart();
}
}
Am i binding wrong since this property gets this value?
SelectedChamber property should be of type ChamberViewModel, try changing it as below:
public ChamberViewModel SelectedChamber
{
get { return _selectedChamber; }
set
{
_selectedChamber = value;
UpdateChart();
}
}
Related
I am currently learning the MVVM design pattern for WPF and I would like to bind my CheckBoxes based on the SelectedItem of my ComboBox which is data binded to a Dictionary where the key is my device serial number and the value is a ViewModel for that device.
Ideally, my SelectedItem should be the value which is IOBoardViewModel.
<ComboBox Name="io_boards_list"
ItemsSource="{Binding IOBoards}" DisplayMemberPath="Key" SelectedValuePath="Value"
HorizontalAlignment="Left" Margin="361,28,0,0" VerticalAlignment="Top" Width="657" Height="35"/>
This is where I am most unclear: how to bind these bool values in my IOBoard Model.
<CheckBox IsChecked="{ Binding Value.io_board.s0 }" Content="Input 0" Canvas.Left="10" Canvas.Top="10" Height="15"/>
<CheckBox IsChecked="{ Binding Value.io_board.s1 }" Content="Input 1" Canvas.Left="10" Canvas.Top="36" Height="15"/>
<CheckBox IsChecked="{ Binding Value.io_board.s2 }" Content="Input 2" Canvas.Left="10" Canvas.Top="63" Height="15"/>
In my IOBoardViewModel I refer to the actual Model which is where I hold my bool value.
public Dictionary<string, IIOBoardViewModel> IOBoards { get; private set; }
public FullIOBoard io_board
{
get { return _io_board; }
}
Here is a snippet from my IOBoard Model:
public bool s0
{
get
{
return _s0;
}
set
{
_s0 = value;
OnPropertyChanged("s0");
}
}
public bool s1
{
get
{
return _s1;
}
set
{
_s1 = value;
OnPropertyChanged("s1");
}
}
public bool s2
{
get
{
return _s2;
}
set
{
_s2 = value;
OnPropertyChanged("s2");
}
}
I would like to know if I have the right idea on how to bind the data together in the MVVM pattern, and if not, I would greatly appreciate insights or advice.
UPDATE:
I have thought of a method that I could use where I bind the SelectedItem of the ComboBox (which would be the Dictionary's identifying serial number to a variable in my ViewModel):
public string SelectedItem
{
get
{
return _SelectedItem;
}
set
{
_SelectedItem = value;
}
}
Now I believe I should bind my IsChecked for the CheckBox to
<CheckBox IsChecked="{ Binding IOBoards[SelectedItem].s0 }" Content="Input 0" Canvas.Left="10" Canvas.Top="10" Height="15"/>
However I am still unable to get the checkbox to update even though I've hardcoded one of the signals to always be true:
_io_board.s0 = true;
_io_board.s1 = (inputSignal & 0x02) == 0x02;
you can bind directly to SelectedItem of ComboBox by referring to it by name:
<CheckBox IsChecked="{ Binding SelectedItem.Value.io_board.s0, ElementName=io_boards_list }"
I have class DimensionType, it has properties Name, Id, etc. I constructed Property in my ViewModel = "dimStyleId" to retrieve selected form ComboBox. I am getting null in this property although I checked it in TextBlock and get it.
<!--Dimension Type Combobox-->
<ComboBox x:Name="DimensionType"
ItemsSource="{Binding dimTypes , Mode=TwoWay}"
SelectedValue="{Binding dimStyleId , Mode=TwoWay}"
SelectedValuePath="DimensionType"
DisplayMemberPath="Name"
Padding="3" />
and here is my VM Class
public class GridsDimViewModel : INotifyPropertyChanged
{
public ElementId dimensionType;
private ElementId _dimStyleId { get; set; }
public ElementId dimStyleId
{
get
{
return _dimStyleId;
}
set
{
if (_dimStyleId != value)
{
_dimStyleId = value;
NotifyPropertyChanged(nameof(dimStyleId));
}
}
}
}
and here is my check textbox which gets the id in it
<TextBlock Text="{Binding dimStyleId}"
Padding="3" />
Swap
SelectedValuePath="DimensionType"
to
SelectedValuePath="Id"
I have a combobox with the following options: "HardDelete", "SoftDelete", "MoveToDeletedItems"
I want the default selection to match with the following property of an EmailAction object:
public DeleteMode DeleteMode { get; set; }
Here is the line of code I'm using to try to set this:
cmboDelMode.SelectedItem = emailActionInstance.DeleteMode.ToString();
Related XAML:
<ComboBox x:Name="cmboDelMode" HorizontalAlignment="Left" Margin="149,218,0,0" VerticalAlignment="Top" Width="120">
<ComboBoxItem Content="HardDelete" HorizontalAlignment="Left" Width="118"/>
<ComboBoxItem Content="SoftDelete" HorizontalAlignment="Left" Width="118"/>
<ComboBoxItem Content="MoveToDeletedItems" HorizontalAlignment="Left" Width="118"/>
</ComboBox>
Currently the combobox is defaulting to being empty so is not working as expected. I am able to use "emailActionInstance.DeleteMode.ToString();" to view the data in a text box, so it seems I might just be setting the selected item incorrectly?
The issue is that setting ComboBox.SelectedItem doesn't work unless the ComboBox contains the item you are setting it to. In your case your ComboBox is filled with three ComboBoxItem objects which have their Content property set to a string. So ComboBox.SelectedItem is a ComboBoxItem. You are trying to set the ComboBox.SelectedItem to a string, which will not equal any of the objects contained in the ComboBox. Therefore, nothing happens.
I would suggest setting up Binding for your ComboBox like here:
<ComboBox ItemsSource="{Binding DeleteModes}" SelectedItem="{Binding SelectedDeleteMode}" />
And then create a ViewModel to bind to. If you bind an Enum to a ComboBox it will display correctly so you won't need to call DeleteMode.ToString():
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
DeleteModes = new ObservableCollection<DeleteMode>
{ DeleteMode.HardDelete, DeleteMode.SoftDelete,
DeleteMode.MoveToDeletedItems };
}
public event PropertyChangedEventHandler PropertyChanged;
DeleteMode _selected_delete_mode;
public DeleteMode SelectedDeleteMode {
get { return _selected_delete_mode; }
set {
_selected_delete_mode = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedDeleteMode"));
}
}
ObservableCollection<DeleteMode> _delete_modes;
public ObservableCollection<DeleteMode> DeleteModes {
get { return _delete_modes; }
set {
_delete_modes = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DeleteModes"));
}
}
public void update_mode(DeleteMode mode) => SelectedDeleteMode = mode;
}
What I'm trying to do
I'm trying to implement the AutoComplete feature on ComboBox without using WpfToolkit. If I'm not wrong, the ComboBox should support the AutoComplete for a simple string item so for example:
<ComboBox IsEditable="True">
<ComboBoxItem>Apple</ComboBoxItem>
<ComboBoxItem>Banana</ComboBoxItem>
<ComboBoxItem>Pear</ComboBoxItem>
<ComboBoxItem>Orange</ComboBoxItem>
</ComboBox>
Current object implementation
actually my ComboBox bound a custom object called CheckedListItem, this object have the following structure:
public class CheckedListItem<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool isChecked;
private T item;
public CheckedListItem() { }
public CheckedListItem(T item, bool isChecked = false)
{
this.item = item;
this.isChecked = isChecked;
}
public T Item
{
get { return item; }
set
{
item = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item"));
}
}
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsChecked"));
}
}
}
this class show as ComboBoxItem a CheckBox near the Text of the Item, similar to:
[] Item1
[] Item2
...
where [] is the Checkbox.
ComboBox structure
The ComboBox look like this:
<ComboBox IsEditable="True" ItemSource={Binding Countries}/>
where Countries is a List of CheckedListItem<Country>, the object country is implemented in this way:
public class Country
{
public string Name { get; set; }
}
the problem on this code is that when I type some text in the ComboBox this doesn't do anything, but should display on the items that contains the string typed.
What I tried so far
I tried to fix this by implementing a PreviewTextInput event, actually I managed in this way:
MyComboBox.IsDropDownOpen = true;
CountryMenuComboBox.ItemsSource = Countries.Where(c => c.Item.Name.Contains(e.Text)).ToList();
but this doesn't working correctly, cause if I type "England", the ItemSource display even all Items.
Any idea to fix this?
Thanks.
Try to set the TextSearch.TextPath property to "Item.Name":
<ComboBox IsEditable="True" ItemsSource="{Binding Countries}"
TextSearch.TextPath="Item.Name">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox IsChecked="{Binding Item.IsChecked}" />
<TextBlock Text="{Binding Item.Name}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I have one ObservableCollection<M> fooBar {get;set;}. The class M.cs looks like this:
public class M{
private int _ID;
public int ID {
get {return this._ID;}
set {this._ID = value;}
}
private string _number;
public int Number {
get {return this._number;}
set {this._number = value;}
}
private string _power;
public int Power {
get {return this._power;}
set {this._power = value;}
}
/*
...
*/
}
Now I want to bind the names of these 3 propertys to a ComboBox. I don't want to do it like this:
<ComboBox>
<ComboBoxItem>ID</ComboBoxItem>
<ComboBoxItem>Number</ComboBoxItem>
<ComboBoxItem>Power</ComboBoxItem>
</ComboBox>
Is there a more comfortable way?
Based on the choose of the first ComboBox I want to fill the second ComboBox. As example I choose in the first ComboBox the property Numberthen the second ComboBox should look like this
<ComboBox
SelectedValue="{Binding ???}"
ItemsSource="{Binding fooBar}"
SelectedValuePath="Number"
DisplayMemberPath="Number"
/>
Maybe someone of you can help me, because I have no idea how to connect both comboboxes.
This is how I would do it:
Make a property on the view model which exposes the properties on the model (class M) which can be selected. This way you explicitly control which properties can be selected.
Make a property to hold the selected value of each combo box.
DisplayMemberPath/SelectedValuePath in ComboBox2 binds to the SelectedValue of ComboBox1.
ViewModel:
// ComboBox 1
public Dictionary<string, string> SelectableProperties = new Dictionary<string, string>()
{
{ nameof (M.ID), "ID" }
{ nameof (M.Number), "Nummer" }
{ nameof (M.Power), "Potenz" }
}
// Selection in combobox 1 (not strictly necessary as it can be handled in view, but you may need to know what SelectedValue represents)
private string _selectedValueMember = String.Empty;
public string SelectedValueMember
{
get { return _selectedValueMember; }
set { _selectedValueMember = value; }
}
// Selection in combobox 2 (object just in case there could be other values than int)
private object _selectedValue = null;
public object SelectedValue
{
get { return _selectedValue; }
set { _selectedValue = value; }
}
public ObservableCollection<M> FooBar{ get; set; }
View:
<ComboBox x:Name="ComboBox1"
Width="100"
Margin="5"
SelectedValuePath="Key"
DisplayMemberPath="Value"
SelectedValue="{Binding SelectedValueMember}"
ItemsSource="{Binding SelectableProperties}">
</ComboBox>
<ComboBox Width="100"
Margin="5"
DisplayMemberPath="{Binding ElementName=ComboBox1, Path=SelectedValue}"
SelectedValuePath="{Binding ElementName=ComboBox1, Path=SelectedValue}"
SelectedValue="{Binding SelectedValue}"
ItemsSource="{Binding FooBar}">
</ComboBox>
For the 1st ComboBox: Use Reflection to get the names of all the properties of class M and put those into the ComboBox.
For the 2nd ComboBox: When selection changes in the 1st one, you get the property name. Now set the SelectedValue binding to the property that was selected in the 1st ComboBox.