I have a ListBox (or a ComboBox, I've tried both) where the items are added directly through ListBoxItem (ComboBoxItem) elements.
The data are CultureInfo objects coming from two ObjectDataProvider resources in the element (or in some place above). The CultureInfo.GetCultureInfo static method is called.
In a word, I would like to have a ListBox/ComboBox populated with some CultureInfo entries.
The data binding works fine, but on setting DisplayMemberPath to one of the CultureInfo properties (such as DisplayName - I would like "English" to be displayed, not "en-US") nothing happens.
Oddly, if I try with ComboBox and select one of the items, DisplayMemberPath works on the selected value (which is shown in the text box), but not on the dropdown list.
My question is: am I missing something? Or does DisplayMemberPath not work with direct items and only when ItemsSource is bound to a collection (just a guess)?
<ListBox x:Name="LangListBox" DisplayMemberPath="DisplayName">
<ListBox.Resources>
<ObjectDataProvider x:Key="EngCultureInfoProvider" ObjectType="{x:Type Globalization:CultureInfo}" MethodName="GetCultureInfo">
<ObjectDataProvider.MethodParameters>
<System:String>en-US</System:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ObjectDataProvider x:Key="ItaCultureInfoProvider" ObjectType="{x:Type Globalization:CultureInfo}" MethodName="GetCultureInfo">
<ObjectDataProvider.MethodParameters>
<System:String>it-IT</System:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</ListBox.Resources>
<ListBoxItem Content="{Binding Source={StaticResource EngCultureInfoProvider}}"/>
<ListBoxItem Content="{Binding Source={StaticResource ItaCultureInfoProvider}}"/>
</ListBox>
Note: using ItemTemplate does not work either.
...
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
...
Currently each ListBoxItem displays result of ToString() method on CultureInfo object.
DisplayMemberPath and ItemTemplate don't work for items, because ListBoxItem are added directly, not created by ListBox.
Add DisplayName in binding path:
<ListBoxItem Content="{Binding Source={StaticResource EngCultureInfoProvider}, Path=DisplayName}"/>
<ListBoxItem Content="{Binding Source={StaticResource ItaCultureInfoProvider}, Path=DisplayName}"/>
or
create default Style for ListBoxItem with custom ContentTemplate:
<ListBox x:Name="LangListBox" DisplayMemberPath="DisplayName">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type Globalization:CultureInfo}">
<TextBlock Text="{Binding DisplayName}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBoxItem Content="{Binding Source={StaticResource EngCultureInfoProvider}}"/>
<ListBoxItem Content="{Binding Source={StaticResource ItaCultureInfoProvider}}"/>
</ListBox>
Related
I have been using wpf xceed third party library for some of the UI components. I really like the way CheckListBox is being displayed at the screen. But I am not able to get the selectedItems bound to any property in the viewmodel (the setter never triggers). Here is the code -
I am using a dataprovider to get values from enum -
<UserControl.Resources>
<ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="DeviceClassDataProvider">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="Model:HANDeviceClass" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
And then the control has been declared something like this -
<ext:CheckListBox Focusable="False" SelectedMemberPath="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}" SelectedItemsOverride="{Binding SelectedDeviceGroups, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Grid.RowSpan="7" Grid.Column="4" Padding="5" BorderThickness="0.8" BorderBrush="Gray" ItemsSource="{Binding Source={StaticResource DeviceClassDataProvider}}"/>
How will i get the selected items in it's viewmodel?
Any quick help would be highly appreciated!
Thanks in advance
Should work provided that SelectedDeviceGroups is a public property that returns an ICollection<HANDeviceClass>:
public ICollection<HANDeviceClass> SelectedDeviceGroups { get; } = new ObservableCollection<HANDeviceClass>();
XAML:
<ext:CheckListBox ItemsSource="{Binding Source={StaticResource DeviceClassDataProvider}}"
SelectedItemsOverride="{Binding SelectedDeviceGroups}" />
<TextBlock Text="{Binding SelectedDeviceGroups.Count}" />
Items will be added to and removed from the source collection as you check and uncheck items respectively.
I have generated RadioButtons from an enumeration as follows.
<ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="GetRadioTypes">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="Enums:RadioTypes"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ItemsControl ItemsSource="{Binding Source={StaticResource GetRadioTypes}}" VerticalAlignment="Center">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<RadioButton Margin="10" GroupName="MyRadios" Checked="RadioButton_Checked" Content="{Binding}" >
</RadioButton>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Now i am interested to Check the first RadioButton generated defaultly.
How can i do that??
If i have IsChecked = "True" for the RadioButtton in ItemTemplate it by default Checks everyone that generates which i dont want to happen.
Thanks in advance
If you change your itemscontrol to, say, a list box you'll have access to the SelectedItem property. Bind that to a property in your viewmodel,SelectedRadio (or whatever), and then set SelectedRadio to the first enum in your vewmodel's constructor.
I want to achieve the following:
My ViewModel exposes a property named 'Categories' which is a collection of CategoryViewModel objects
Each CategoryViewModel object exposes a property called 'Items' which is a collection of strings*.
On my View, I want a TabControl with a TabItem for each object in the 'Categories' collection.
The Content of each TabItem should be a xceed DataGrid control displaying the contents of the selected tab's Items collection.
<TabControl ItemsSource="{Binding Categories}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding CategoryName}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<xcdg:DataGridControl
ItemsSource="{Binding Items}"
AutoCreateColumns="True">
</xcdg:DataGridControl>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
This works ok when I bind directly to the ItemsSource property of the DataGridControl. However, in order to utilize all of the functionality of the DataGridControl, I need to bind the ItemsSource property of the DataGridControl to a DataGridCollectionViewSource object that is bound to my Items collection. I do this when the grid ISN'T nested in another control by creating a DataGridCollectionViewSource object in the Resources section of the UserControl and binding to that.
<UserControl>
<UserControl.Resources>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
Source="{Binding Items}" />
</UserControl.Resources>
<Grid>
<xcdg:DataGridControl
ItemsSource="{Binding Source={StaticResource GridData}}"
AutoCreateColumns="True">
</xcdg:DataGridControl>
</Grid>
</UserControl>
How do I need to structure the XAML so that when the TabControl is being bound, a DataGridCollectionViewSource object is created for each TabItem so that the DataGridControl that is generated within the content of the TabItem can be bound to it?
Clear as mud, right? :)
Thanks!
Notes:
*In the real solution the collection contains objects of a class that is more complex than a simple string, but a string was used to make the example more simple.
OK, this is a bit of a long-shot, but could you use the DataGrid.Tag ...
<TabControl.ContentTemplate>
<DataTemplate>
<xcdg:DataGridControl
ItemsSource="{Binding RelativeSource={RelativeSource Self}, Path=Tag}"
AutoCreateColumns="True">
<xcdg:DataGridControl.Tag>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
Source="{Binding Items}" />
</xcdg:DataGridControl.Tag>
</xcdg:DataGridControl>
</DataTemplate>
</TabControl.ContentTemplate>
Or ... resources can be defined on any FrameworkElement, so you could try:
<TabControl.ContentTemplate>
<DataTemplate>
<xcdg:DataGridControl
ItemsSource="{Binding Source={StaticResource GridData}}"
AutoCreateColumns="True">
<xcdg:DataGridControl.Resources>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
Source="{Binding Items}" />
</xcdg:DataGridControl.Resources>
</xcdg:DataGridControl>
</DataTemplate>
</TabControl.ContentTemplate>
I don't use the eXceed Grid so cannot test whether these work - just a couple of ideas to try!
Colin E.
You can use x:Shared="True" attribute on a resource. That means a new instance is created for every use of that resource.
Example:
<UserControl.Resources>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
x:Shared="False"
Source="{Binding Items}" />
</UserControl.Resources>
Ok, this is an embarassingly simple-looking problem, but is driving me crazy. I'm learning about DataTemplating and am trying to apply a very VERY simple ItemTemplate to a ListBox.
However, when I run my app, the template is completely ignored and I just get the standard-looking listbox, whereas in fact I'd expect to see a list of checkboxes with 'Test' along side.
I've tried this several times and always the same result. I've checked several resource on Google and all have the same kind of syntax for defining and ItemTemplate on a ListBox, so I really cannot see where I'm going wrong.
Code...
<Grid x:Name="LayoutRoot">
<ListBox x:Name="TestList"
SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox Content="Check this checkbox!"/>
<TextBlock>Test</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Items>
<ListBoxItem>Bob</ListBoxItem>
<ListBoxItem>Jim</ListBoxItem>
<ListBoxItem>Dave</ListBoxItem>
<ListBoxItem>Larry</ListBoxItem>
<ListBoxItem>Tom</ListBoxItem>
</ListBox.Items>
</ListBox>
</Grid>
Any help greatly appreciated. Sorry for such a dumb-seeming question, but I've really fallen at the first hurdle here :(
AT
ItemTemplate wont work when you put ListBoxItem directly as items. General concept is you databind a CRL collection to the ListBox.ItemsSource and then specify the ItemTemplate. Check the below code.
<Grid x:Name="LayoutRoot">
<ListBox x:Name="TestList" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox Content="Check this checkbox!"/>
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Items>
<sys:String>Bob</sys:String>
<sys:String>Jim</sys:String>
<sys:String>Dave</sys:String>
<sys:String>Larry</sys:String>
<sys:String>Tom</sys:String>
</ListBox.Items>
</ListBox>
</Grid>
where sys is xmlns:sys="clr-namespace:System;assembly=mscorlib"
In this way, there are 5 ListBoxItems getting generated in the background and added to the ListBox.
You can use ItemContainerStyle instead of ItemTemplate if you want to add ListBoxItems directly to the ListBox.
Doing so, however, is only recommended when you need unique characteristics on a per item level.
If you are planning on all the items looking the same or making a dynamic list using ItemsSource, I would recommend you add strings (or another custom object) to your list and use ItemTemplate to display your items. (see Jobi Joy's answer)
Here's an example using ItemContainerStyle:
<ListBox
x:Name="TestList"
SelectionMode="Multiple">
<ListBox.ItemContainerStyle>
<Style
TargetType="ListBoxItem">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="ListBoxItem">
<StackPanel>
<CheckBox
Content="Check this checkbox!" />
<TextBlock
Text="{TemplateBinding Content}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.Items>
<ListBoxItem>Bob</ListBoxItem>
<ListBoxItem>Jim</ListBoxItem>
<ListBoxItem>Dave</ListBoxItem>
<ListBoxItem>Larry</ListBoxItem>
<ListBoxItem>Tom</ListBoxItem>
</ListBox.Items>
</ListBox>
For some reason DataTemplate can still be ignored if the ListBox is populated using ItemsSource e.g:
<ListBox Name="Test" x:FieldModifier="public" ItemsSource="{Binding UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Note that this is bound to an ObservableCollection containing objects (TextAdapter : INotifyPropertyChanged) with one property: string Text {...}
I have a listbox and I want to iterate over a collection of Bars in my Foo-object.
<ListBox DataContext="{Binding Path=Foo.Bars}" >
<ListBox.Items>
<ListBoxItem>
<ContentControl DataContext="{Binding Path=.}" />
</ListBoxItem>
</ListBox.Items>
</ListBox>
This is the datatemplate I want to use.
<DataTemplate DataType="{x:Type Bar}">
<Label Content="hello stackoverflow" />
</DataTemplate>
If I snoop (--> examine by using the tool Snoop) my application, I notice that the entire collection of Bars is bound to the ContentControl, in stead of just 1.
How can I properly bind so the iteration over the collection goes fine?
You can just set the DataTemplate, and WPF does all the work. Set the ItemsSource to a list of Bar items, and then define a DataTemplate for Bar items.
<ListBox ItemsSource="{Binding Path=Foo.Bars}">
<ListBox.Resources>
<DataTemplate DataType="{x:Type Bar}">
<Label Content="hello stackoverflow" />
</DataTemplate>
</ListBox.Resources>
</ListBox>
You could also set the ItemsTemplate directly by using <ListBox.ItemTemplate> instead of <ListBox.Resources>
See Data Binding Overview at MSDN.
First add your namespace to the Window element (Intellisense) :
xmlns:local="clr-namespace:yourenamespace"
Then the following XAML ( in Window.Resources is a clean way to do it ) :
<Window.Resources>
<ObjectDataProvider x:Key="DataProvider" ObjectType="{x:Type local:Foo}"/>
<DataTemplate x:Key="Template" >
<TextBlock Text="{Binding Bar}"/>
</DataTemplate>
</Window.Resources>
Place the Listbox :
<ListBox DataContext="{Binding Source={StaticResource DataProvider}}" ItemsSource="{Binding Bars}" ItemTemplate="DynamicResource Template" />
But, it depends on your code-behind object, you have to set a constructor to initialise public properties within your object which are ObservableCollection<> preferably (There is some restriction rules with object instance in XAML).