WPF change selected value in one ComboBox by another ComboBox in MVVM - c#

I am having a problem. I have two combobox in WPF first:
<ComboBox commands:PropertyChangeBehavior.Command="{Binding GetCurrentsModuleCommand}" SelectedIndex="0">
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem IsEnabled="True">All</ComboBoxItem>
<CollectionContainer Collection="{Binding Source={StaticResource ResourceKey=AxmModulesCombo}}" />
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
</StackPanel>
Lets call it Source and it is binded to command:
public ICommand GetCurrentsModuleCommand => new Command(module =>
{
SelectedAxmModule = module.ToString();
Stuff(module);
});
And this combo box has no SelectItem property (well it don't needs any as parameters are only pass to method).
And a Target CombxBox
<ComboBox ItemsSource="{Binding AxmModules}"
SelectedItem="{Binding SelectedAxmModule, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
SelectedValuePath="{Binding SelectedAxmModules}"
IsSynchronizedWithCurrentItem="True"/>
Witch SelectedItem property is binded to:
private string selectedAxmModule;
public string SelectedAxmModule
{
get => selectedAxmModule;
set
{
selectedAxmModule = value;
OnPropertyChanged();
}
}
Now those combo boxes are similar in values, now I want to do if I click value on source as you see in source command i want to select same value from source (I handled values from source and not in target in code so that is irrelevant).
I tried adding Update property and SelectedValuePath but no good value in target combo box is still empty after selecting value from source, and OnPropertyChange works as inteded. Is there a way to achieve this?

If AxmModules is an IEnumerable<byte>, SelectedAxmModule should be a byte property. You cannot set a string property to a byte value. The types must match.
And SelectedValuePath is superfluous when using SelectedItem.

Since you have
IsSynchronizedWithCurrentItem="True"/>
Then the selecteditem should be the current. You should work with the current item of the collectionview rather than binding selecteditem.
You can read more, probably more than you want to read, about collectionview and this sort of stuff here:
https://social.technet.microsoft.com/wiki/contents/articles/26673.wpf-collectionview-tips.aspx
Also.
See this
SelectedValuePath="{Binding SelectedAxmModules}"
The selectedvaluepath is a string not a binding. It should be the name of whichever field you want to use.
If, for whatever reason, you want to bind to the current item in a collection then you can use the / notation.
https://social.technet.microsoft.com/wiki/contents/articles/29859.wpf-tips-bind-to-current-item-of-collection.aspx
I'm not sure how this is going to fit with a composite collection though. I prefer a separate control to indicate selection of "all" and hence wouldn't use a composite collection in this way. You might want to consider that approach yourself.

Related

How to bind combo-box to a certain item in an ObservableCollection list - WPF?

I have this code:
C#:
public ObservableCollection<My_EDMX_Table> formatsList = new ObservableCollection<My_EDMX_Table>();
XAML:
<ComboBox
Grid.Row="1"
Grid.Column="5"
Margin="0, 5, 5, 5"
Name="CB_1"
ItemsSource="{Binding formatsList}"
SelectedValue="{Binding formatsList[2], Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="True"
Opacity="1"
DisplayMemberPath="formatNaziv"
SelectionChanged="CB_1_SelectionChanged" />
I want to bind certain item in the list, in this case the first element in formatsList. Although the app compiles I don't get my combo box set to a chosen value from its ItemSource list.
What is the right way to bind observable collection and set component to appropriate value?
What is the right way to bind observable collection and set component to appropriate value?
The right way would be to bind the SelectedItem property of the ComboBox to a source property of the view model that you set to formatsList[2] in the view model class.
You don't decide which item that is the "certain" one in the view. It's the view model that decides this and returns the "certain" one that the view then binds to. Remember that your application logic should be implemented in the view model class.
If you always want to bind to the third item initially for some reason, you might as well hardcode the SelectedIndex property to 2 in the XAML.

Combobox selected item binding inside Datagrid in WPF not working

I am having a issue with a Combo box inside a datagrid in WPF.
I want the arrow on the combo box to be visible even when it is not in editing mode. I couldn't achieve this behavior with DataGridComboBoxColumn which otherwise was working fine. To fix this appearance issue I had to use normal combo box.
<DataGridTemplateColumn Header="Parameter Group" MinWidth="150" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource GroupList}}"
DisplayMemberPath="ParameterGroupName"
IsSynchronizedWithCurrentItem="True"
SelectedValuePath="ParameterGroupName"
SelectedValue="{Binding Path=ParameterGroup,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Now the problem is that the selected item binding is not working. Any item selected for a row is applying for all. I am not sure what's wrong here.
The item source is-
private ObservableCollection<ParameterGroupModel> _parameterGroupList;
public ObservableCollection<ParameterGroupModel> ParameterGrpList
{
get
{
return _parameterGroupList;
}
set
{
_parameterGroupList = value;
NotifyPropertyChanged("ParameterGrpList");
}
}
And the selected value is a simple string inside the model.
Can someone please help?
With the CellTemplate you 'duplicate" the same xaml code in each cell at running time, thus the same bindings. So each cell refers to the same datasource and the same selectedItem object.
You must define somewhere a collection of object on which each row can bind separately its selected item and refer to it specifically in each cell
(one possible solution may be to use a multibinding with the selectedItemCollection and the row number for exemple to determine which item of the selectedItemCollection your row has to bind to)

Two-way binding combobox to enum

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.

Changing Data Context for Data Template clears Combo Box selection

I have a TreeView that permits the user to select different items. The display for each item is determined using Data Templates with the DataType set to the appropriate ViewModel type. The DataContext is automatically set based on the selected item in the tree view to the appropriate ViewModel.
Here's the problem:
One of the DataTemplates has a ComboBox bound to an ObservableCollection to get the list of items and a property to get/set the SelectedValue in the ViewModel.
When I select one item of this type, and then select another item of the same type, the ComboBox displays blank instead of the correct selected item. It appears that the Combo Box is setting the SelectedValue property to NULL immediately after the transition to the new item, and then never updating.
<ComboBox Margin="1,0"
ItemsSource="{Binding ItemsToSelect}"
SelectedValue="{Binding SelectedValue}"
SelectedValuePath="ValuePath" DisplayMemberPath="DisplayPath"
IsEnabled="{Binding CanSelectItem}">
</ComboBox>
The really strange part is if I select an item of a different type between selecting items of the same type, it always displays correctly.
I've tried ignoring the NULL value in the SelectedValue setter, and that didn't work regardless of whether I also raised the PropertyChanged event or not.
private MyObject selectedValue;
public MyObject SelectedValue
{
get
{
return selectedValue;
}
set
{
if (value != null)
{
this.selectedValue = value;
}
this.OnPropertyChanged("SelectedValue");
}
}
Looking at the similar questions while writing this lead me to an interesting attribute that I hadn't found yet - IsSynchronizedWithCurrentItem from this question. At first, I thought this solved the problem, but alas it just changes the behavior somewhat.
With this attribute set to True, the combo doesn't entirely clear its selection, but instead just marks the first item as selected. So, instead of being set to NULL, now the SelectedValue property is being set to the first item in the list.
Anyone have any ideas for a solution?
If I understand your problem correctly, a couple of things are going on here.
First you do not have Mode=TwoWay, UpdateSourceTrigger=PropertyChanged} set in your bindings.
Second, the property binding will only update if there is a change in the value itself.
Check this out Data Binding
I figured out a work around, but it isn't quite what I wanted.
I changed the binding to use SelectedItem instead of SelectedValue, and the issue doesn't occur.
I got the idea from this question.
So I changed
SelectedValue="{Binding SelectedValue}"
To (and renamed my ViewModel Property):
SelectedItem="{Binding SelectedItem}"
After updating the uses of this property in the ViewModel, everything worked.

Find a control within a ListViewItem

I have a ListView displaying a list of items containing mainly two properties.
Each of these properties should ideally be chosen from two comboboxes.
Moreover, the choices available in the second combobox is depends on the first.
So here is the idea of the code I used:
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<ComboBox Name="combo1"
ItemsSource="{DynamicResource combo1Source}"
SelectedItem="{Binding FirstProperty}"
SelectionChanged="combo_SelectionChanged">
<ComboBox Name="combo2"
ItemsSource="{DynamicResource combo2Source}"
SelectedItem="{Binding SecondProperty}">
</StackPanel>
<DataTemplate>
<ListView.ItemTemplate>
</ListView>
The thing is, I don't know how to get the reference to combo2 from within combo_SelectionChanged (in C#).
Could you show me how to proceed?
The easiest thing you can do is add a Tag to combo1:
<ComboBox Name="combo1" Tag="{x:Reference combo2}" ... />
Which you then can just get from the sender in the event handler, e.g.
var combo2 = (sender as FrameworkElement).Tag as ComboBox;
Alternatively you could get the StackPanel from the Parent property and just take (ComboBox)Children[1]. I would not do this though as is breaks if the structure of your template changes.
You should not have a reference to combo2, but you should update the Collection combo2Source which is bound as ItemsSource for combo2...
So in the combo_SelectionChanged you just load the possible values for the actual selection of combo1 to the combo2Source Collection.
EDIT: To prevent thats its for all items the same:
Add a ValueConverter which choses for a selectedItem the corresponding collection of possible values:
<ComboBox ItemsSource="{Binding ElementName=Combo1, Path=SelectedItem, Converter={StaticResource SubSelectionConverter}}" />
Example of ValueConverter:
private Dictionary<Object, List<Object>> _PossibleValues;
public object Convert(Object data, ....)
{
if(PossibleValues.ContainsKey(data))
{
//return the possible values for the actual selected parent item
return(PossibleValues(data));
}
return null;
}
Can have look here on my question and different responses and the solution I found for my specific project:
Find an element in Data Template
Hope this helps.
Regards.

Categories

Resources