Reputation: 31
I'm trying to figure out how to bind a List of ListBoxItems and have the correct DisplayMemberPath be shown on my control. I need to use a list of ListBoxItems because my control is accessing properties such as ActualHeight/Width, which I lose if I bind the ItemsSource to a List of State
public class State
{
public string LongName { get; set; }
public string ShortName { get; set; }
}
I have a AllItems, a List of State. I am populating my ListBox's ItemsSource as follows:
BoxItems = new ObservableCollection<MyListBoxItem>(AllItems.Select(i => new MyListBoxItem() { Content = i }).ToList());
I want my DisplayMemberPath to be LongName. I've tried many different ways of modifying the .xaml to properly display the LongName (New York, New Jersey, Florida, etc), but I always end up with namespace.classname in my listbox. I've attempted setting the ListBox's DisplayMemberPath and ItemsSource in the .xaml and in the .xaml.cs.
I've tried many different things such as setting the content control and adding a data template in the .xaml.
Upvotes: 2
Views: 2342
Reputation: 169270
The DisplayMemberPath
refers to a property of the type T
in the IEnumerable<T>
ItemsSource of the ListBox
. So if you set the ItemsSource
to an ObservableCollection<MyListBoxItem>
, it is the MyListBoxItem
class that must have a LongName
property for you to be able to set the DisplayMemberPath
property to "LongName".
I need to use a list of ListBoxItems because my control is accessing properties such as ActualHeight/Width, which I lose if I bind the ItemsSource to a List of State.
Any item that you add to the Items
/ItemsSource
property that is not a ListBoxItem
is implicitly wrapped in a ListBoxItem
container. You can set any properties of this one using the ItemContainerStyle
property of the ListBox
. This means that you could add Height
and Width
properties to the State
class and bind to these provided that you set the ItemsSource
to an IEnumerable<State>
:
<ListBox x:Name="lb" ItemsSource="{Binding AllItems}" DisplayMemberPath="LongName" Loaded="ListBox_Loaded">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Height" Value="{Binding Height}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
You could also get a reference such a container once it has been loaded, using the ItemContainerGenerator
:
private void ListBox_Loaded(object sender, RoutedEventArgs e)
{
foreach (var item in lb.Items)
{
var container = lb.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
if (container != null)
{
//...
}
}
}
Setting the ItemsSource to an IEnumerable<ListBoxItem>
is not a good idea.
Upvotes: 0
Reputation: 128070
Creating an ObservableCollection<MyListBoxItem>
doesn't seem to make sense.
Better bind directly to AllItems
:
<ListBox ItemsSource="{Binding AllItems}"
DisplayMemberPath="LongName"/>
Instead of setting DisplayMemberPath
, you may set the ItemTemplate
property:
<ListBox ItemsSource="{Binding AllItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding LongName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Upvotes: 2