2

我有一个带有嵌入式组合框的列表框:

<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
    <DataTemplate>
        <ComboBox Width="100" IsEditable="False" Height="20">
            <TextBlock Text="Opt#1"></TextBlock>
            <TextBlock Text="Opt#2"></TextBlock>
            <TextBlock Text="Opt#3"></TextBlock>
        </ComboBox>
    </DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

我想在未选择 ListBox 行时将 ComboBox 显示为简单文本(例如 TextBlock),并在选择 ListBox 行时将其显示为 ComboBox。

我在想动态替换 ComboBox 模板就可以了。如何做到这一点?

谢谢, 莱斯泽克

4

3 回答 3

0

我会简单地使用一种样式来替换被选中ListBox.ItemTemplate时的样式。ListBoxItem

这是一个简单的例子

<ListBox.Resources>
    <DataTemplate x:Key="TextBoxTemplate">
        <TextBlock Text="{Binding }" />
    </DataTemplate>

    <DataTemplate x:Key="ComboBoxTemplate">
        <ComboBox SelectedItem="{Binding }">
            <ComboBoxItem>Opt#1</ComboBoxItem>
            <ComboBoxItem>Opt#2</ComboBoxItem>
            <ComboBoxItem>Opt#3</ComboBoxItem>
        </ComboBox>
    </DataTemplate>

    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="Template" Value="{StaticResource TextBoxTemplate}" />
        <Style.Triggers>
            <Trigger Property="IsSelected" Value="True">
                <Setter Property="Template" Value="{StaticResource ComboBoxTemplate}" />
            </Trigger>
        </Style.Triggers>
    </Style>
</ListBox.Resources>

我实际上建议使用IsKeyboardFocusWithin而不是IsSelected作为触发器属性,因为模板可以让您与它们交互而无需将项目设置为选中。

于 2012-04-16T15:02:23.453 回答
0

感谢 Josh 和 Rachel 为我指明了正确的方向。

我想出了一个类似于 Rachel 建议的解决方案。我的问题是我无法使 ItemTemplateSelector 工作,而且我不知道如何从我的列表框中传递状态 IsSelected。我也不能使用 DataTemplate,因为我的 ListBox 项比单个元素复杂得多(为了示例,我在上一篇文章中对其进行了简化)。

无论如何,我想出了以下解决方案。它不是很优雅,但它有效:

  1. 我在应用程序资源中定义了一种新样式:

    <Style x:Key="TextBlockTemplate" TargetType="ComboBox">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <TextBlock Text="{Binding}" Margin="3" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
  2. 我将 SelectionChanged 和 PreviewMouseDown 处理程序附加到我的列表框:

  3. 我定义了 MyListBox_PreviewMouseDown:

    私人无效 MyListBox_PreviewMouseDown(对象发送者,MouseButtonEventArgs e)
    {
        // 抓取选中的列表框项。
        对象元素 = (e.OriginalSource as FrameworkElement).DataContext;
        var item = MyListBox.ItemContainerGenerator.ContainerFromItem(element)
            作为列表框项;

        // 将 ListBox 中的行标记为选中。
        如果(项目!= null)
            item.IsSelected = true;
    }

  1. 我定义了 MyListBox_SelectionChanged:
    私人组合框 prevComboBox = null;
    私人无效 MyListBox_SelectionChanged(对象发送者,SelectionChangedEventArgs e)
    {
        // 抓取列表框。
        ListBox list = 作为 ListBox 的发件人;

        // 虽然只能选择一项,
        // 我们遍历所有选定的项目。
        foreach(列表中的 MyDataItem 数据。SelectedItems)
        {
            var item = list.ItemContainerGenerator.ContainerFromItem(dat) as ListBoxItem;
            // FindElement 是在可视化树中查找元素的辅助方法。
            组合框 cbo = FindElement(item, "MyComboBox") as ComboBox;

            if (cbo != prevComboBox)
            {
                cbo.Style = null;

                if (prevComboBox != null)
                    prevComboBox.Style =
                        (样式)Application.Current.Resources["TextBlockTemplate"];

                上一页组合框 = cbo;
            }
        }
    }

谢谢, 莱斯泽克

于 2012-04-18T00:45:40.093 回答
0

交换模板的最佳方法是使用 ListBox 的 ItemTemplateSelector 属性并将其设置为您创建的继承自 DataTemplateSelector 的类。

这是一个提供示例的链接:http: //msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector.aspx

于 2012-04-16T14:33:58.473 回答