Unable to bind collection to ComboBox in silverlight - c#

I've a ObservableCollection, when I want to display this ObservableCollection with CheckBox I am simply binding the contents to CheckBox but when I want to display the same collection by using ComboBox I am unable to do that. Any suggestions?
XAML: Display collection using CheckBox --WORKS
<ItemsControl ItemsSource="{Binding Synonyms}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Margin="0,5,0,0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Display items in CheckBox-->
<CheckBox Content="{Binding Display}" Margin="10,0,0,0" /> // Display is the collection.
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Output:
XAML: Display collection using ComboBox --NOTHING OVER HERE
<ItemsControl ItemsSource="{Binding Synonyms}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Margin="0,5,0,0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Display items in ComboBox.-->
Approach - 1
<ComboBox>
<ComboBoxItem Content="{Binding Display}"/>
</ComboBox>
Approach - 2
<ComboBox ItemsSource="{Binding Path=Synonyms}" DisplayMemberPath="Display"/>
Approach - 3
<ComboBox >
<ComboBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Green" BorderThickness="1" Padding="5">
<TextBlock Text="{Binding Path=Display,StringFormat='Display: {0}'}" />
</Border>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Output:
I want to display items(one,two,three, etc.) inside oneComboBox with Select All option. I've tried several approaches but nothing. What am I missing here?

The checkbox is not designed to hold multiple items unlike the Combobox so implementing a system designed for the checkbox is not relevant for the combobox.
To solve your issue, remove the combobox from the ItemsControl and have it stand on its own:
<ComboBox ItemsSource="{Binding Synonyms}" DisplayMemberPath="Display"/>
Which tells the combobox to bind its ItemsSource to the data context which is unspecified, which is fine, so it then gets it's parent's data context. That process works its way up to each parent until it finds a bound data context (most likely the page's datacontext to a VM instance).
Assuming that the data context is valid at some point in the visual tree, it will bind to that instance and look for a property named Synonyms. From the Synonyms property it will use that as a list to display items.
To show (display) text in the combobox (instead defaulting to the item's ToString()) the combobox will show the string from the item's property Display.
Giving a list of items in one drop down.

The short answer, is you should use a ComboBox as the root element, not ItemsControl. CompboBox is just a specialized version of ItemsControl.
<ComboBox ItemsSource="{Binding Synonyms}" DisplayMemberPath="Display"/>
The longer answer.
ComboBox derives from ItemsControl, so you get all the features the base class, plus additional features.
ItemsControl (and its derived classes) provides a way of repeating a set of data in the UI. The DataTemplate is where you specify what UI you want for each "row" of data in the Synonyms source.
What you are doing is asking Silverlight to create a separate ComboBox for each underlying data row.
You can still use a DataTemplate within the ComboBox. Like this.
<ComboBox ItemsSource="{Binding Synonyms}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Display items in CheckBox-->
<TextBox Text="{Binding Display}"
Margin="10,0,0,0"
FontWeight="Bold" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Related

How to nest ItemsControl with multiple ItemsSource?

I have a ConfigList object with a name and a Dictionary and I need to nest ItemsControls with different ItemsSource.
I tried to do it this way :
<ItemsControl x:Name="TestStep" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding Path=ConfigList }" HorizontalAlignment="Center" VerticalAlignment="Center">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Ictrl.Nom}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl
ItemsSource="{Binding Path=Param}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Key}" />
<TextBlock Text=" : " />
<TextBlock Text="{Binding Path=Value}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ItemsControl>
When I start my application, I've got this error :
System.Windows.Markup.XamlParseException : '' Adding a value to the
collection of type 'System.Windows.Controls.ItemCollection' threw an
exception. ' line number '25' and line position '14'. '
Internal Exception
InvalidOperationException: Invalid operation when ItemsSource is in
use. Access and edit items with ItemsControl.ItemsSource.
Any idea what ​​the problem is?
You set an ItemsSource on the ItemsControl. The data template is used to create the controls that display the data. The created items are then put into the Items collection of the ItemsControl. If you add an element to the ItemsControl directly in XAML this will put them into the Items collection, too. Doing both is not allowed. You either specify an ItemsSource or add to Items directly. From the documentation:
Note that you use either the Items or the ItemsSource property to specify the collection that should be used to generate the content of your ItemsControl. When the ItemsSource property is set, the Items collection is made read-only and fixed-size.
However, in your case this is not the real issue, because your markup is wrong for what you want to achieve. If you you really intended to nest ItemsControls, you would simply change the data template for the outer ItemsControl to contain another ItemsControl that binds to a collection property within the outer data item. Since there is already a TextBox, you have to use a panel (e.g. StackPanel) to host multiple controls in the template.
<ItemsControl x:Name="TestStep" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding Path=ConfigList }" HorizontalAlignment="Center" VerticalAlignment="Center">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Ictrl.Nom}" />
<ItemsControl ItemsSource="{Binding Path=Param}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Key}" />
<TextBlock Text=" : " />
<TextBlock Text="{Binding Path=Value}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you want to have a hierarchical view of your data, using a TreeView might be a better fit.

Auto-scroll Listbox based on TextBox text

In WPF and MVVM pattern, I have a TextBox and a ListBox. The ListBox is bound to a collection of items using a DataTemplate. The default count for this collection is about 50 or so.
What I wanted to achieve is a filter-like action. If it's possible, I wouldn't like to change the list view or anything like that, but simply to scroll to the item corresponding to the TextBox match, preferably without selecting it.
I've seen some examples and solutions using CollectionView and Filter (couldn't get it to work btw), and some using auto-scroll to the end of the list or to a new added item, but none specific to my case.
My Listbox is structured as follows:
<ListBox IsTextSearchEnabled="True" HorizontalAlignment="Stretch" Margin="6,49,0,0" Name="lbObjectA" VerticalAlignment="Stretch" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type src:Dto}">
<StackPanel Height="20" Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" Margin="0,3,0,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Binding SelectedIndex to a different Collection then the Collection of the itemsSource

Hi I am developing an application for WinRT with MVVM-light. What i am trying to do is fill a combobox with items, for example 4 kinds of fruit. And my SelectedItem should be the first kind of fruit to which the combobox is bound. This works but, the next step is that i want to make the selectedIndex change. For example when The first kind of fruit is sold out then the SelectedIndex should automattically change to the second item in the Collection Of my Combobox.
So if you would want to buy 10 pieces of fruit you would get 10 comboboxes on your screen in which you can select the kind of fruit, when you have selected an apple in 4 of them and there are no apples anymore then the selectedindex of the other comboboxes should change to the second kind of fruit.
I know it is a bit of a confusing question.
Basically what i need is to be able to bind my Selectedindex to a property in a Collection that is different from the Collection of my combobox. I will give you a bit of xaml that will hopefully explain a bit more:
</ListView>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel IsHitTestVisible="{Binding HitTest}" Orientation="Horizontal">
<TextBlock Text="{Binding Day, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:dd MMM yyyy}' }"></TextBlock>
<ComboBox Width="196" ItemsSource="{Binding Path=FruitKind.FruitList, Source={StaticResource Locator}}" SelectedIndex="{Binding Path=FruitKind.FruitComboBoxItem, Source={StaticResource Locator}, ElementName={Binding Path=FruitIndex}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FruitKind}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I'm not sure if this is possible by the way.
thnx
Bind to the selected item instead of index. THis allows you to work with a object/property of the viewmodel that you can modify any way you want:
ie:
<ComboBox Width="196" ItemsSource="{Binding Path=FruitKind.FruitList, Source={StaticResource Locator}}" SelectedItem="{Binding Path=FruitKind.FruitObject, Source={StaticResource Locator}, ElementName={Binding Path=FruitIndex}}">

WPF Databinding stackpanel

Im a beginner in WPF programming, coming from .NET 2.0 C#.
Im trying to make a horizontal StackPanel which should be filled with data from a table in a database. The problem is that I want it to display an image with some text from the table below and then stack those two items horizontally.
Here's some pseudo-code to display what I want to do:
<StackPanel Orientation="horizontal" ItemsSource="{Binding Path=myTable}">
<StackPanel>
<Image Source="User.png"/>
<Label HorizontalAlignment="Center" Content="{Binding Path=UserName}"></Label>
</StackPanel>
</StackPanel>
I simply cannot figure oout how to do this.
Julien's answer is correct for your written description, however, looking at your XAML, it appears you are looking for something like the following:
<DataTemplate x:Key="UserDataTemplate">
<StackPanel>
<Image Source="User.png"/>
<Label HorizontalAlignment="Center" Content="{Binding Path=UserName}" />
</StackPanel>
</DataTemplate>
<ItemsControl x:Name="UserList" ItemTemplate="{StaticResource UserDataTemplate}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
You definately need an ItemsControl (or some derivation of) to bind your source to. Then you can change the the orientation by setting it's items panel (which I believe is a VirtualizingStackPanel with Vertical orientation by default) so just set it to a VirtualizingStackPanel with Horizontal Orientation. Then you can set the ItemsTemplate for each of your items to the layout you desire (an image stacked on top of text bound from your database).
Basically, you want to use a control capable of displaying an enumeration of objects. The control capable of this is the class ItemsControl and all of its descendants (Selector, ListBox, ListView, etc).
Bind the ItemsSource property of this control to a list of objects you want, here a list of users you've fetched from the database. Set the ItemTemplate of the control to a DataTemplate that will be used to display each item in the list.
Sample code:
In a Resources section (for example Window.Resources):
<DataTemplate x:Key="UserDataTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="User.png"/>
<Label HorizontalAlignment="Center" Content="{Binding Path=UserName}" />
</StackPanel>
</DataTemplate>
In your Window/Page/UserControl:
<ItemsControl x:Name="UserList" ItemTemplate="{StaticResource UserDataTemplate}" />
In your code behind:
UserList.ItemsSource = ... // here, an enumeration of your Users, fetched from your db

Bind Dictionary to ItemsControl in C#/WPF

I'm trying to bind KeyValuePair Elements from a Dictionary to a ItemsControl.
My Dictionary has 15 Elements and the following code shows me 15 TextBoxes:
<WrapPanel Name="PersonsWrapPanel" Grid.Row="0">
<ItemsControl ItemsSource="{Binding Persons}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" Width="auto">
</WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Value.Text}"></TextBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</WrapPanel>
Unfortunately without any TextBox content (which would be Key or Value).
Any ideas?
Perhaps try binding directly to the values of the dictionary:
ItemsSource="{Binding Persons.Values}"
If I am understanding your XAML properly, each object in the dictionary has a field called "Text" to which you are trying to bind. If so and you make the above changes, you will need to change your DataTemplate as well:
<TextBox Text="{Binding Text}" />
See this article for more info. HTH.
I solved it by using this line:
<TextBox Text="{Binding Value, Mode=OneWay}"></TextBox>
The code on http://www.dev102.com/2008/03/07/binding-a-wpf-control-to-a-dictionary/ doesn't seem to work.
Let us say you have a Dictionary called RowValues, with both the [key, value] defined as [string, string].
Now to bind to the Value Pair of this dictionary, you can do the following:
<ItemsControl ItemsSource="{Binding RowValues.Values}" >
To display the text (Value), you can bind as:
<TextBlock Text="{Binding}"/>

Categories