I am trying to add items to a ComboBox (say Name="labelComboBox") at runtime when I pressed an add button (say with Name="add2labels" Click="add2labels_Click"). But the ComboBox cannot show the values I newly added. What did I miss?
The following is the event handler for the add button:
private List<String> labels = new List<String>();
... ...
private void add2labels_Click(object sender, RoutedEventArgs e)
{
labels.Add("new value");
labelComboBox.ItemsSource = labels;
}
P.S. I am pretty sure the values were added to List<String> labels correctly (its count did increase each time).
Updated with workable solutions (3 ways) :
Use ObservableCollection (#AnatoliyNikolaev's answer).
Change List<String> labels to ObservableCollection<String> labels. And only need to call labelComboBox.ItemsSource = labels; once in all.
Use Binding (#HarshanaNarangoda's answer).
Add ItemsSource="{Binding Path=labels}" to ComboBox's properties.
Use Refresh() (#EliranPe'er's anwer).
Change the event handler to:
... ...
labelComboBox.ItemsSource = labels;
labelComboBox.Items.Refresh(); // new added
You should use ObservableCollection<T> instead of List<String>:
ObservableCollection represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
Try using labelComboBox.Items.Refresh();
Combobox has a display and value member to add values to combo-box you need to specify both.
try this
ComboboxItem item = new ComboboxItem();
item.Text = "new value";
item.Value = 12;
labels.Items.Add(item);
I think You have to change some code in XAML to following.You have to bind data to your Combo Box.
<ComboBox ItemsSource="{Binding}" Height="23" HorizontalAlignment="Left" Name="comboBox1" />
Related
Background
The application has a list view binded to a list of "Jobs", of which the properties are editable by some comboboxes (with two way binding). The data context of the comboboxes is changed to the currently selected job via the SelectionChanged event of the list view.
The combobox value is bound to a property of Job. The itemssource of the job is changed to completely different list upon DataContextChanged.
Layout of widgets
Issue
The binded property linked to the combobox of Job is set to null when changing the DataContext.
By clicking through the list of Jobs, all the properties bound to any combobox are set to null.
Assumed Problem
I may be incorrect in this assumtion...
As the datacontext is switched, either the old selected Job or the new selected Job is set to null as the itemsource does nto contain the value stores in on of the either the new or old selected Job.
Debugging Attempts (Edit)
I've noticed the the value of the property of the Job was set to null before the SelectedItem of the list of jobs was changed.
Question
How can the value of the binded property of Job be preserved when switching the datacontext of the ComboBox to an itemsource that does not contain SelectedValue?
Relevant Code (Abridged - Binding to other widgets works as expected)
<ComboBox x:Name="ContactField" Grid.Column="1" Grid.Row="3" Margin="2,1" Grid.ColumnSpan="3" DisplayMemberPath="Value" SelectedValuePath="Id" SelectedValue="{Binding Contact,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectionChanged="ContactField_SelectionChanged"/>
Code Behind - Changing Items Source
private void UpdateCustomerDependancies()
{
imprintDataSetTableAdapters.CustomerContactsTableTableAdapter rpcdtta = new imprintDataSetTableAdapters.CustomerContactsTableTableAdapter();
IList<ComboData> customers = new List<ComboData>();
if (LeftFieldPanel.DataContext != null) //Where LeftFieldPanel contains all comboboxes
{
Job currentJob = (Job)LeftFieldPanel.DataContext;
foreach (DataRow item in rpcdtta.GetDataBy(currentJob.CustomerCode).Rows)
{
customers.Add(new ComboData() { Id = item.ItemArray[0].ToString(), Value = item.ItemArray[1].ToString() });
}
ContactField.ItemsSource = customers;
}
}
Code Behind - Changing Data Context
private void jobTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (jobTree.SelectedItem.GetType() == typeof(Job))
{
DelGrid.Visibility = Visibility.Hidden;
Job j = (Job)jobTree.SelectedItem;
MessageBox.Show(j.Contact);
LeftFieldPanel.DataContext = j; //Switch datacontext
RightFieldPanel.DataContext = j; //switchdata context
}
}
According to this answer, and my own research, it is not possible to simply bind and hope for this best. Therefore, my workaorund to this solution is the following. I have generalised the code to make it applicable to other circumstances.
1) Upon the change of datacontext, append new items to the list, without removing old items:
private void ListView1_SelectedItemChanged(...) {
List<ComboData> comboitems = ((IList<ComboData>)ComboBox1.ItemsSource).ToList();
//Add new items to comboitems here
ComboBox1.ItemsSource = comboitems; //Rebind
}
2) Upon opening the dropdown of the combobox, get the itemsource and remove old items only
private void ComboBox1_DropDownOpened(...) {
List<ComboData> comboitems = ((IList<ComboData>)ComboBox1.ItemsSource).ToList();
//Remove old items from comboitems here
ComboBox1.ItemsSource = comboitems; //Rebind
}
Apologies if this is not clear enough, I felt that posting the real code would make it rather difficult to understand out of the context.
This has solved my own issue.
Alternate Solution
See above and add items without remove old ones. Then replace the entire itemssource only on a dropdownopened event.
I have a problem with the combobox in WPF. You know that when you open the combobox and you start typing, that the selected index of the combobox is moving to the element that starts with the same letter. Well i actually need the same thing but a bit different.
The items in the combobox are actually binded to a class. This class has 2 properties, a Code property ( contains for example "XF15A") and a Description property ( contains for example "Radio"). I used a data template that actually binded the text for an combobox item to "[code] - [Description]".
Now when the type "XF" is goes to the combobox item that starts "XF". But what i now also need is that when you type "Ra" it should go to the combobox item "XF15A - Radio".
Do you guys know how to solve this? I'm also open for existing usercontrols.
Thanks,
My code is not quite what you want, but should give you an example of how you could do it yourself:
You got to handle PreviewTextInput yourself and let your algorithm decide which item to select. Here's a simple example:
XAML:
<ComboBox x:Name="cb" PreviewTextInput="ComboBox_PreviewTextInput">
<ComboBoxItem>adsfsf</ComboBoxItem>
<ComboBoxItem>adsfsf</ComboBoxItem>
<ComboBoxItem>acdd</ComboBoxItem>
<ComboBoxItem>adsfsf</ComboBoxItem>
</ComboBox>
Code Behind:
private void ComboBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
cb.IsDropDownOpen = true;
foreach (ComboBoxItem item in cb.Items)
{
var str = (string)item.Content;
if(str.Contains(e.Text))
{
cb.SelectedItem = item;
break;
}
}
}
Currently I am working on multiselect combobox custom control with combobox inherited, which attached a listbox to a combobox with a multiple selection mode. But now I face a problem when passing the selected items to my custom control in view. I use the listbox selectionchanged event to update my selected item in my combobox. I'm able to implement this approach on selecteditem, it manages to pass one selected item to my view. But I want to pass all the selecteditems to my view.
And this is what I have done so far.
MultiSelectCombobox.xaml <-- My custom control xaml inherited from combobox
<ComboBox.Template>
...
<Popup>
<ListBox SelectionMode="Multiple" ItemsSource="{TemplateBinding ItemsSource}"
SelectionChanged="ListBox_SelectionChanged">
...
</ListBox>
</Popup>
MultiSelectCombobox.xaml.cs
public partial class MultiSelectComboBox : ComboBox
...
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox lb = sender as ListBox;
this.SelectedItem = lb.SelectedItem;
}
MainWindow.xaml.cs
MultiComboBox mComboBox = (sender as MultiComboBox);
MessageBox.Show(this, mComboBox.SelectedItem.ToString());
use this 2 line in some combobox event to display selecteditem.
I search through few posts, but I'm still unable to find any solution, I would appreciate if you could provide some guidance for me.
Try this...
MultiSelectCombobox.xaml.cs
public partial class MultiSelectComboBox : ComboBox
{
...
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(IList),
typeof(MultiSelectComboBox));
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox lb = sender as ListBox;
this.SelectedItem = lb.SelectedItem;
this.SelectedItems = lb.SelectedItems;
}
}
Keep in mind that this would only work for one way selection. If you want to make sure it is only used to get the selected items and that nobody tries to set them this way, you could turn the DependencyProperty into a readonly one and use an IEnumerable instead of an IList.
If you wanna support two way selection changes (changing the selected items from code and not only from user interaction with the ListBox) then you'd have to add a property changed callback to the DependencyProperty and maybe use an ObservableCollection to listen for changes in the collection, and update the ListBox selection accordingly.
Hi I have a ListBox and set it up as follows in xaml:
<dxdo:LayoutPanel Caption="Raw Data File Names" ItemWidth="2*">
<ListBox ItemsSource="{Binding FilteredFileNames}" SelectionMode="Extended" SelectionChanged="Selector_OnSelectionChanged"/>
</dxdo:LayoutPanel>
When I handle the event in code-behind each time I select multiple items (via shift-down plus mouse click) I noticed that the first item is never included in the array of items:
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var vm = DataContext as HistoricalDataImportRawDataViewModel;
vm.SelectedFileNames = e.AddedItems.Cast<string>().ToList();
}
What am I doing wrong? Is it because AddedItems only include the items beyond the initial selection? What can I do to get the complete collection of items? Please note that I have to use SelectionMode="Extended". Is the omission of the first item intended or a bug?
The AddedItems property tells which item was added to the selected items. If you are interested about all the items that are selected, you have to access ListBox property SelectedItems.
var listbox = (ListBox) sender;
var selectedItems = listbox.SelectedItems
.Cast<string>()
.ToList();
I programmatically add DataGrid:
System.Windows.Controls.DataGrid dataGrid = new System.Windows.Controls.DataGrid();
dataGrid.GridLinesVisibility = DataGridGridLinesVisibility.None;
dataGrid.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
dataGrid.Background = Brushes.White;
DataGridTextColumn textColumn = new DataGridTextColumn();
textColumn.Width = 250;
textColumn.Header = "Account";
textColumn.Binding = new Binding("Account");
dataGrid.Columns.Add(textColumn);
When I add Item:
Globals_Liker.list_datagrid[tabControl1.SelectedIndex].Items.Add(Globals_Liker.list_item[tabControl1.SelectedIndex][i]);
But if I doubleclick on Items I have error:
"EditItem" is not allowed for this view.
How to make that error does not pop up?
You should not update the Items directly of your DataGrid but rather set the ItemsSource to the collection. DataGrid will generate the view out of the itemsource that implements IEditableCollectionView interface in order to allow the editing. This interface has function EditItems() which let the editing happen.
So in order solve this problem. Create the ObservableCollection property in your VM/Code behind and set the DataGrid ItemsSource to it like
ObservableCollection<Type> MyCollection{get;set;}
Globals_Liker.list_datagrid[tabControl1.SelectedIndex].ItemsSource = MyCollection;
In your constructor you can initialize this collection by newing it. And whenever you want to add item in your DataGrid, just add the item in the Observable collection (MyCollection), it will be shown on grid and will be editable.
I seen this error in 3 cases
case1 : this error shown if double clicking the datagrid then(custom datagrid which contains processed data like analysis)
Simply, Set in Datagrid IsReadOnly="True"
case2 : this error shown after editing the datagrid, must set during RowEditEnding
(sender as DataGrid).CommitEdit(DataGridEditingUnit.Row);
case3 : this error shown after RowEditEnding event, then must see where the datagrid is reloading the data, it can happen if viewsource or datagrid is already in use and we try to override the data manually
Let me know if any new cases you seen
this works for me
InitializeComponent();
datagrid.BeginningEdit += (s, ss) => ss.Cancel = true;
I tried wiht IsReadOnly="True", but it doesn't allow me to check and uncheck the checkbox on the datagrid