ListBox中ComboBox的动态模板

时间:2012-04-16 14:09:37

标签: wpf xaml combobox

我有一个带有嵌入式ComboBox的ListBox:

<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模板就可以了。怎么做到这一点?

谢谢, 莱谢克

3 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分: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作为触发器属性,因为模板可以让您与它们进行交互,而无需将项目设置为选中。

答案 2 :(得分: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处理程序附加到我的ListBox:

  3. 我定义了MyListBox_PreviewMouseDown:

  4. 
        private void MyListBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            // Grab the selected list box item.
            object element = (e.OriginalSource as FrameworkElement).DataContext;
            var item = MyListBox.ItemContainerGenerator.ContainerFromItem(element) 
                as ListBoxItem;
    
            // Mark the row in the ListBox as selected.
            if (item != null)
                item.IsSelected = true;
        }
    
    
    1. 我定义了MyListBox_SelectionChanged:
    2.     private ComboBox prevComboBox = null;
          private void MyListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
          {
              // Grab the list box.
              ListBox list = sender as ListBox;
      
              // Although there could be only one item selected, 
              // we iterate over all selected items.
              foreach (MyDataItem dat in list.SelectedItems)
              {
                  var item = list.ItemContainerGenerator.ContainerFromItem(dat) as ListBoxItem;
                  // FindElement is a helper method to find an element in a visual tree.
                  ComboBox cbo = FindElement(item, "MyComboBox") as ComboBox;
      
                  if (cbo != prevComboBox)
                  {
                      cbo.Style = null;
      
                      if (prevComboBox != null)
                          prevComboBox.Style = 
                              (Style)Application.Current.Resources["TextBlockTemplate"];
      
                      prevComboBox = cbo;
                  }
              }
          }
      
      

      谢谢, 莱谢克