I have a ComboBox
<ComboBox ItemsSource="{Binding ElementName=listBox, Path=SelectedItem.Values}" SelectedItem="{Binding Path=SelectedValue}"/>
On changing ItemsSource I can get an error in SelectedItem, because there is no SelectedItem in new ItemsSource. I am need to change SelectedIndex to 0 on ItemsSource changing.
How to do it?
What if before changing the ItemsSource you set it's selected index to -1 and then set the source.
combo.SelectedIndex = -1;
combo.ItemsSource = list;
Related
I am building an app in WPF (MVVM).
The user is to make a selection in a ComboBox, and the choice is supposed to filter the results available in a DataGridComboBoxColumn (DGCBC) in a DataGrid.
But I am at a loss at how to bind the ComboBox SelectedItem to the DGCBC. I did manage to have the ComboBox filter the results of a second ComboBox, but that logic does not seem to transfer well to the DGCBC.
What I have tried:
My ComboBox:
<ComboBox
DisplayMemberPath="PropertyName1"
ItemsSource="{Binding Collection1}"
Loaded="{s:Action NameOfMethodToPopulateComboBox}"
SelectedItem="{Binding PropertyHolder, UpdateSourceTrigger=PropertyChanged}"/>
The PropertyHolder is ran when an item is selected in the ComboBox, and if it's not null, it runs the method that adds to the ObservableCollection which is bound to the DGCBC. It looks like this:
private ClassName _currentSelectedItem;
public ClassName CurrentSelectedItem {
get { return this,._selectedItem; }
set { SetAndNotify(ref this._selectedItem, value);
if (value != null) {
FillDataGridComboBoxColumn();
}
}
}
The method, FillDataGridComboBoxColumn() looks like this (abbreviated):
DataSet ds = new();
// Code to run stored procedure
// CurrentSelectedItem is given as parameter value
DataTable dt = new();
dt = ds.Tables[0];
MyObservableCollection.Clear();
for (int i = 0; i < dt.Rows.Count; i++) {
DataRow dr = dt.NewRow();
dr = dt.Rows[i];
HolderClass holderClass = new(); // this is the class that is bound to the observablecollection
holderClass.PropertyName = dr["PropertyName2"].ToString();
MyObservableCollection.Add(holderClass);
This is the XAML for the DataGrid and the DataGridComboBoxColumn:
<DataGrid
AutoGenerateColumns="False"
ItemsSource="{Binding MyObservableCollection}">
<DataGridComboBoxColumn
SelectedValueBinding="{Binding PropertyName2, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="PropertyName2"
DisplayMemberPath="PropertyName2"
ItemsSource="{Binding MyObservableCollection}">
/>
</DataGrid>
When I debug, the DataGridComboBoxColumn is able to get the correct number of rows - but they're just empty placeholders; blanks. If I put a break-point in the code, I see that the collection is indeed loaded with the correct values, but they're just not showing.
I am guessing I am doing something wrong with the binding for the DGCBC.
Thank you.
The DataGridComboBoxColumn ItemSource had to be set as a Static Resource:
<Window.Resources>
<CollectionViewSource x:Key="MyObservableCollection" Source="{Binding MyObservableCollection}"/>
</Window.Resources>
And then, in the XAML for the DataGridComboBoxColumn:
<DataGridComboBoxColumn
ItemsSource="{Binding Source={StaticResource MyObservableCollection}}"
DisplayMemberPath="Property2">
</DataGridComboBoxColumn>
So what i am trying to accomplish is that i am trying to bind 2 properties from 1 list to 2 different ComboBoxes.
code:
combobox1.DataContext = class.repository;
combobox2.DataContext = class.repository;
and in xaml
<ComboBox x:Name="combobox1" ItemsSource="{Binding Name}"/>
<ComboBox x:Name="combobox2" ItemsSource="{Binding Password}"/>
example - repository[0] = "NAME1"
The result i get is when i open ComboBox looks like:
1 item - N
2 item - A
3 item - M
and so on..
and result i want is
1 item = NAME1
2 item = NAME2
...
Thanks for replies.
If repository is a string[], you should bind the ItemsSource to the DataContext itself:
<ComboBox x:Name="combobox1" ItemsSource="{Binding}"/>
If repository is an IEnumerable<YourClass> where YourClass is a type with a Name and a Password property, you should also set the DisplayMemberPath property:
<ComboBox x:Name="combobox1" ItemsSource="{Binding}" DisplayMemberPath="Name" />
<ComboBox x:Name="combobox2" ItemsSource="{Binding}" DisplayMemberPath="Password"/>
You should use DisplayMemberPath property of the ComboBox to specify you want to see the value of propery "Name".
Let's say you have one Listbox in WPF with items such as 1,2,3,4,5 etc. How do you make another Listbox, right next to first one, that shows its items according to selection in the first Listbox? So if you select "item 2" in Listbox you'd get 2A, 2B,2C etc in Listbox2, if you select "item 3" you'd get 3A, 3B, 3C etc in Listbox3
Can't embed the picture yet but here's the example of what i need
There is an example of how to implement such cascading ComboBoxes according to the recommended MVVM design pattern available here: https://blog.magnusmontin.net/2013/06/17/cascading-comboboxes-in-wpf-using-mvvm/
You could bind the SelectedItem property of the first ListBox to a source property of your view model. In the setter of this one you then set another collection property that you bind the ItemsSource property of the second ListBox to, e.g.:
<ListBox ItemsSource="{Binding Numbers}" SelectedItem="{Binding SelectedNumber}" />
<ListBox ItemsSource="{Binding SubNumbers}" />
private object _selectedNumber;
public object SelectedNumber
{
get { return _selectedNumber; }
set
{
_selectedNumber = value;
NotifyPropertyChanged();
//set items
SubNumbers = new List<string> { "3A", "3B", "..." };
NotifyPropertyChanged("SubNumbers");
}
}
Make sure that your view model class implements the INotifyPropertyChanged interface and raises change notifications for this to work: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx
Alternatively, if your model classes are defined in such a way that each item in the first ListBox has a collection property that returns its related items, you could bind the second ListBox directly to a property of the SelectedItem in the first one:
<ListBox x:Name="lb1" ItemsSource="{Binding Numbers}"/>
<ListBox x:Name="lb2" ItemsSource="{Binding SelectedItem.SubProperty, ElementName=lb1}" />
I am having trouble assigning the a combobox item by using an enum value that the combobox source is assigned to.
The XAML
<ComboBox HorizontalAlignment="Left"
x:Name="cmbName"
VerticalAlignment="Top"
Width="120" Margin="79,48,0,0">
<ComboBox.ItemsSource>
<CompositeCollection>
<ListBoxItem Content="Please Select"/>
<CollectionContainer Collection="{Binding Source={StaticResource Enum}}" />
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
The C# that is trying to set the combobox to an item in the enum
// The problem, the assignment doesn't work.
cmbName.SelectedItem = Enum.value;
I can only set a item by using the combobox SelectedIndex
cmbName.SelectedIndex = 2;
But this is hardcoding the index so if the enum changes, so will the value.
So how can I set the combobox by the enum value?
Thanks
It's very hard to tell what your problem is because you haven't fully documented your scenario. As such, all that I can do is to show you how to do what you want. As I prefer to work with properties, I won't be using any Resources for this example, but I'm sure that you'll still be able to relate this solution to your problem.
So, first we have a test enum and some properties and some initialisation:
public enum TestEnum
{
None, One, Two, Three
}
private TestEnum enumInstance = TestEnum.None;
public TestEnum EnumInstance
{
get { return enumInstance; }
set { enumInstance = value; NotifyPropertyChanged("EnumInstance"); }
}
private ObservableCollection<TestEnum> enumCollection = new ObservableCollection<TestEnum>() { TestEnum.None, TestEnum.One, TestEnum.Two, TestEnum.Three };
public ObservableCollection<TestEnum> EnumCollection
{
get { return enumCollection; }
set { enumCollection = value; NotifyPropertyChanged("EnumCollection"); }
}
...
EnumCollection.Add(TestEnum.One);
EnumCollection.Add(TestEnum.Two);
EnumCollection.Add(TestEnum.Three);
EnumInstance = TestEnum.Three;
Then we have a ComboBox:
<ComboBox Name="ComboBox" ItemsSource="{Binding EnumCollection}"
SelectedItem="{Binding EnumInstance}" />
If you run the application, then at this point the selected ComboBoxItem should read Three. Because the ComboBox.SelectedItem is data bound to the EnumInstance property, setting...:
EnumInstance = TestEnum.Two;
... is roughly the same as:
ComboBox.SelectedItem = TestEnum.Two;
Both of these would select the Two value in the ComboBox. However, note this example:
EnumInstance = TestEnum.None;
Setting either the EnumInstance or the ComboBox.SelectedItem property to TestEnum.None would have no effect in the UI because there is no TestEnum.None value in the data bound collection.
I apologise that my answer was descriptive enough, however, the reason why I haven't set my enum as a property as Sheridan has described below is that I need an extra string value in my combo which you can see is "Please Select" and unfortunately, I cannot put this in the enum.
But Sheridan's method and logic is the way to go if you want to do this.
However, for my problem, I simply just used
ComboBox.SelectedValue = Enum.Value.ToString();
Thanks
I'm using Entity Framework as my database source and need to convert a Linq query "var" type to an ObservableCollection. I then need to bind the ObservableCollection to a ComboBox on WPF form; binding to ItemsSource, DisplayMemeberPath, SelectedValuePath and SelectedValue.
Here is Code:
using (PulseContext pc = new PulseContext())
{
var maritalcodes = from m in pc.CodeMaster
where m.Type == "16"
select new { m.Code, m.Description };
prop.ClientData.Options = new ObservableCollection<object>(maritalcodes);
}
Problem is the ComboBox is showing this as "{ Code = ????, Description = ???? }" instead of bind to code for value and description for display. What do I have to do to get the ComboBox to bind to the individual elements?
You need to set SelectedValuePath and DisplayMemberPath like this:
prop.ClientData.Options = new ObservableCollection<object>(maritalcodes);
prop.ClientData.Options.SelectedValuePath = "Code";
prop.ClientData.Options.DisplayMemberPath = "Description";
Or you can set them in xaml like this:
<ComboBox ItemsSource="{Binding Path=maritalcodes}"
SelectedValuePath="Code"
DisplayMemberPath="Description" />
<ComboBox ItemsSource="{Binding Path=maritalcodes}"
SelectedValuePath="Code"
DisplayMemberPath="Description"
SelectedValue="{Binding Path=Code}"/>
I hope this will help.