【问题标题】:Set DisplayMemberPath for ListBoxItem's Content为 ListBoxItem 的内容设置 DisplayMemberPath
【发布时间】:2017-03-01 18:41:08
【问题描述】:

我试图弄清楚如何绑定 ListBoxItems 列表并在我的控件上显示正确的 DisplayMemberPath。我需要使用 ListBoxItems 列表,因为我的控件正在访问诸如 ActualHeight/Width 之类的属性,如果我将 ItemsSource 绑定到状态列表,我会丢失这些属性

public class State
{
    public string LongName { get; set; }
    public string ShortName { get; set; }
}

我有一个 AllItems,一个状态列表。我正在填充我的 ListBox 的 ItemsSource,如下所示:

BoxItems = new ObservableCollection<MyListBoxItem>(AllItems.Select(i => new MyListBoxItem() { Content = i }).ToList());

我希望我的 DisplayMemberPath 为 LongName。我尝试了许多不同的方法来修改 .xaml 以正确显示 LongName(纽约、新泽西、佛罗里达等),但我的列表框中总是以 namespace.classname 结束。我尝试在 .xaml 和 .xaml.cs 中设置 ListBox 的 DisplayMemberPath 和 ItemsSource。

我尝试了许多不同的方法,例如设置内容控件和在 .xaml 中添加数据模板。

【问题讨论】:

  • 'Content = i.LongName'
  • 我正在尝试制作一个通用控件,它接受List&lt;object&gt;,所以我不知道字段的名称。我公开了另一个属性,用于设置 DisplayMemberPath。

标签: c# wpf xaml listbox listboxitem


【解决方案1】:

创建ObservableCollection&lt;MyListBoxItem&gt; 似乎没有意义。

最好直接绑定到AllItems

<ListBox ItemsSource="{Binding AllItems}"
         DisplayMemberPath="LongName"/>

您可以设置ItemTemplate 属性,而不是设置DisplayMemberPath

<ListBox ItemsSource="{Binding AllItems}">
    <ListBox.ItemTemplate>
         <DataTemplate>
             <TextBlock Text="{Binding LongName}"/>
         </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

【讨论】:

  • 在上面的代码 sn-p 中它应该只是ListBoxItem,而不是MyListBoxItem。我需要使用 ListBoxItems,因为它们公开了我在控件其他地方使用的高度/宽度(ActualHeight 和 ActualWidth)的属性。如果我只绑定一个List&lt;State&gt;,我会丢失这些属性。
  • DataTemplate 中的元素也有大小。并且可以通过ListBox的ItemContainerGenerator.ContainerFromItem方法得到一个包含数据项的ListBoxItem。
  • 有时这会返回 null,即使该项目存在于 itemsource 中。
  • 可能是由于虚拟化。如果您没有大量的项目,请在 ListBox 上设置VirtualizingPanel.IsVirtualizing="False"
  • 我试过了。我试过同时使用ContainerFromIndexContainerFromItem。鉴于我的上述情况,没有办法绕过设置正确的 DisplayMemeberPath 吗?如果没有,我想我将不得不管理后面代码中的值 - 使用反射来获取正确的值并将该字符串绑定到ListBoxItem 并将这些值映射到传入的原始项目(类)。跨度>
【解决方案2】:

DisplayMemberPath 指的是ListBoxIEnumerable&lt;T&gt; ItemsSource 中T 类型的属性。因此,如果您将ItemsSource 设置为ObservableCollection&lt;MyListBoxItem&gt;,则MyListBoxItem 类必须具有LongName 属性才能将DisplayMemberPath 属性设置为“LongName”。

我需要使用 ListBoxItems 列表,因为我的控件正在访问诸如 ActualHeight/Width 之类的属性,如果我将 ItemsSource 绑定到状态列表,我会丢失这些属性。

您添加到Items/ItemsSource 属性的任何不是ListBoxItem 的项目都隐式包装在ListBoxItem 容器中。您可以使用ListBoxItemContainerStyle 属性设置此属性的任何属性。这意味着您可以将HeightWidth 属性添加到State 类并绑定到这些属性,前提是您将ItemsSource 设置为IEnumerable&lt;State&gt;

<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>

您也可以在加载后使用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)
        {
            //...
        }
    }
}

将 ItemsSource 设置为 IEnumerable&lt;ListBoxItem&gt; 不是一个好主意。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-25
    • 1970-01-01
    相关资源
    最近更新 更多