How to insert item to combobox after binding wpf - wpf

I want to add an item to the combobox after binding it.
for example:
this.cbCategory.ItemsSource = categoryList;
this.cbCategory.DisplayMemberPath = "CategoryName";
this.cbCategory.SelectedValuePath = "CategoryID";
i want to add("All", "%") as the first one.
Geetha.

This is very simple using a CompositeCollection:
<ComboBox DisplayMemberPath="CategoryName" SelectedValuePath="CategoryID">
<ComboBox.ItemsSource>
<CompositeCollection>
<my:Item CategoryName="All" CategoryID="%" />
<CollectionContainer Collection="{Binding CategoryList}" />
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
How it works: The CompositeCollection produes the "All" item followed by all of the items in the CategoryList collection. Note that <my:Item ... /> is the constructor for your item class. You will need to change it to your actual namespace and class name.
Important advice: I notice you are setting some ComboBox properties in code-behind. This is a very bad practice. You should use XAML as shown above.

You'll break the binding if you try to add it later and will no longer receive updates.
Why not just add your 'extra' item before you bind it?

Related

WPF cascading ComboBoxes not binding when window loads

I'm using WPF and MVVM, and have a support ticket window that has cascading ComboBoxes as follows. The first is bound to an ObservableCollection<ProblemCode> on the view model. The ProblemCode objects have a self-referencing property to their child codes, down to a level of four codes. The XAML for the ComboBoxes looks like this (simplified, and only three shown for brevity)...
<ComboBox ItemsSource="{Binding ElementName=Root, Path=DataContext.ProblemCodes, Mode=TwoWay}"
Name="ProblemCodeLevel1"
DisplayMemberPath="Description"
SelectedValuePath="ID"
SelectedValue="{Binding ProblemCode1ID, Mode=TwoWay}" />
<ComboBox ItemsSource="{Binding ElementName=ProblemCodeLevel1, Path=SelectedItem.Children}"
Name="ProblemCodeLevel2"
DisplayMemberPath="Description"
SelectedValuePath="ID"
SelectedValue="{Binding ProblemCode2ID, Mode=TwoWay}" />
<ComboBox ItemsSource="{Binding ElementName=ProblemCodeLevel2, Path=SelectedItem.Children}"
Name="ProblemCodeLevel3"
DisplayMemberPath="Description"
SelectedValuePath="ID"
SelectedValue="{Binding ProblemCode3ID, Mode=TwoWay}" />
When I load a window for a new ticket, the first ComboBox is correctly populated. Selecting an item populates the second and so on. When I save the ticket, the data is correctly saved.
However, when I save the ticket and reopen the window, only the first ComboBox has the selected item set. The other ComboBoxes don't have anything set.
I guess that the first ComboBox is set as the data is available when the data binding takes place. At that stage, as the first ComboBox is data bound, the second one doesn't yet have any items, so doesn't get bound. Same for the third and so on.
Anyone any suggestions as to how to get the binding working? I probably could hack this by adding code to catch various events, but apart from breaking the MVVM pattern, it sounds like none of those situations that would end up convoluted and buggy.
Generally speaking you shouldn't bind directly to elements, you should be binding to properties in your view model. That way you know the property notification is being done properly and you can add breakpoints etc to confirm the bindings are all working as well. In this particular case you need to add something like SelectedItem="{Binding Level1Item}" to your first ComboBox and then add a property for it in your view model:
public ProblemCode _Level1Item;
public ProblemCode Level1Item
{
get { return this._Level1Item; }
set
{
if (this._Level1Item != value)
{
this._Level1Item = value;
RaisePropertyChanged(() => this.Level1Item);
}
}
}
Then your second ComboBox binds to this property instead of Element.SelectedItem.Children:
<ComboBox ItemsSource="{Binding Level1Item.Children}"
...etc...
Repeat for the second and third ComboBoxes and you'll have the functionality you're after.

Binding ObservableCollection of strings to templated ListBox

I have this collection
ObservableCollection<string> Urls { get; set; }
inside my data context class. I have a binding to it in my list box:
<ListBox ItemsSource="{Binding Urls}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding .}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The data is diplayed in the list box, the two corresponding-not-shown-here buttons with commands Add and Delete work as well, however, the changing the TextBox does not affect the contents of the collection.
I have tried Mode=TwoWay in binding, but I figured that it is turned on already. I have tried some other options like Validate=OnPropertyChange, however, there is still nothing get updated.
How to make the TextBox inside that templated items in ListBox actually update the Urls property of a datacontext class?
You cannot modify strings; use a wrapper class with one string property, then bind the TextBox to said property. That way the strings in the property can be replaced with the edited ones.

Combobox CompositeCollection

I want two comboboxes with collection with empty element.
I Use two comboboxes with:
<ComboBox x:Name="itemEditPageComboBox"
...
ItemsSource="{StaticResource ItemsColl}"
....
/>
Collections:
<CompositeCollection x:Key="ItemsColl">
<ComboBoxItem Content="" />
<CollectionContainer Collection="{Binding Source={StaticResource ElementsCollection}}" />
</CompositeCollection>
<CollectionViewSource x:Key="ElementsCollection" Source="{Binding Path=...}" />
behaviour
Sequentially choose two comboboxes, after it - one of them is removed empty element.
Error:
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='ComboBoxItem'
Please tell me what to do?
Best regards!
You cannot use the same ComboBoxItem in two ComboBoxes, also the error should be quite clear: If you add a ComboBoxItem to a ComboBox which has an ItemTemplate defined, that won't be applied to that ComboBoxItem because it already has the type of the created containers. This error may or may not be a problem, depending on what you want.
If you want to use the collection for two ComboBoxes you should add a string or if you want something more complex an instance of a class (which should probably have an implicit DataTemplate associated with it). Do not add a ComboBoxItem directly.

Bind RibbonComboBox.SelectionBoxItem

I'm trying to bind the item selected in a RibbonComboBox to a property of an object. The problem I'm encountering is that the RibbonComboBox.SelectionBoxItem only provides a get accessor; therefore, I cannot bind it to anything in the XAML.
Any ideas how to bind the item to the property of an object? I could use a regular ComboBox is there another more appropriate control?
xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
<ribbon:RibbonComboBox
ItemsSource="{Binding Source={StaticResource CollectionOfPossibleChoices}}"/
SelectionBoxItem="{Binding Path=PropertyToBindTo}"/> <!--Not valid-->
RibbonComboBox is unlike ComboBox (which i, also, find confusing). Try this;
<ribbon:RibbonComboBox>
<ribbon:RibbonGallery SelectedItem="{Binding Path=PropertyToBindTo}">
<ribbon:RibbonGalleryCategory ItemsSource="{Binding Source={StaticResource CollectionOfPossibleChoices}}" />
</ribbon:RibbonGallery>
</ribbon:RibbonComboBox>
MSDN Reference

WPF StaticResource bound to subproperty

I have a class thats created as a resource:
<Window.Resources>
<Model:MyModel x:Key="model" />
</Window.Resources>
The MyModel class has a cli property named Foo. I want the selected value in a combobox to be bound to this property. I thought I could do this but Im getting errors:
<ComboBox SelectedItem="{Binding Source={StaticResource model.Foo}}" />
Heres the error:
Cannot find resource named '{model.Foo}'.
Where did I go wrong? What extra parameters do I need to specify to properly bind to a subproperty?
You almost have it correct. You want to use a combination of the Binding's Path property and its Source property. So use one of the following (they are equivalent.)
{Binding Foo, Source={StaticResource model}}
or
{Binding Path=Foo, Source={StaticResource model}}
Hope this helps.

Resources