使用ItemsControl的页面指示符忽略数据模板

时间:2014-07-01 22:58:05

标签: wpf binding itemscontrol

我尝试使用ItemsControl创建页面指示符。我们的想法是绑定到TabControl的标签,并为每个标签显示一个圆圈,颜色由触发器确定,该触发器检查标签是否被选中:

<ItemsControl ItemsSource="{Binding Path=Items, ElementName=ATabControl}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>

  <ItemsControl.ItemTemplate>
    <DataTemplate DataType="{x:Type TabItem}">
      <Ellipse x:Name="PageIndicator" Width="6" Height="6" Margin="2,0" />

      <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=IsSelected}" Value="False">
          <Setter TargetName="PageIndicator" Property="Fill" Value="White" />
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=IsSelected}" Value="True">
          <Setter TargetName="PageIndicator" Property="Fill" Value="Blue" />
        </DataTrigger>
      </DataTemplate.Triggers>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

它编译没有错误,但我得到了列出的标签的名称,而不是圆圈。实际上,它完全忽略了ItemTemplate/DataTemplate。实际上,如果我删除后者,显示屏保持不变。

1 个答案:

答案 0 :(得分:1)

将UI元素绑定在两个不同的容器中时始终存在问题。因为一个UI元素只能有1个父元素,所以最后一个父元素将具有实际元素,因此将从之前的父元素中删除相同的元素。

在您提到的问题中,您尝试将UI元素TabItems绑定到items控件,该控件有效地从制表符控件中拉出原始元素,并将它们作为item控件的子元素。

为了解决这个问题,我提出了一个解决方案,将这些UI元素包装在一个类中,并连接所需的属性。

我尝试使用转换器

进行解决方案

XAML

<StackPanel xmlns:l="clr-namespace:CSharpWPF">
    <StackPanel.Resources>
        <l:TabItemsConverter x:Key="TabItemsConverter" />
    </StackPanel.Resources>
    <TabControl x:Name="ATabControl">
        <TabItem Header="item 1" />
        <TabItem Header="item 2" />
        <TabItem Header="item 3" />
    </TabControl>
    <ItemsControl ItemsSource="{Binding Path=Items, ElementName=ATabControl,Converter={StaticResource TabItemsConverter}}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"
                            HorizontalAlignment="Center" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Ellipse x:Name="PageIndicator"
                         Width="6"
                         Height="6"
                         Margin="2,0"
                         Fill="Gray" />
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding Path=IsSelected}"
                                 Value="False">
                        <Setter TargetName="PageIndicator"
                                Property="Fill"
                                Value="Gray" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=IsSelected}"
                                 Value="True">
                        <Setter TargetName="PageIndicator"
                                Property="Fill"
                                Value="Blue" />
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

转换器类

namespace CSharpWPF
{
    public class TabItemsConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            List<TabItemWrapper> result = new List<TabItemWrapper>();

            foreach (TabItem item in (ItemCollection)value)
            {
                result.Add(new TabItemWrapper(item));
            }
            return result;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        class TabItemWrapper : DependencyObject
        {
            public bool IsSelected
            {
                get { return (bool)GetValue(IsSelectedProperty); }
                set { SetValue(IsSelectedProperty, value); }
            }

            // Using a DependencyProperty as the backing store for IsSelected.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty IsSelectedProperty =
                DependencyProperty.Register("IsSelected", typeof(bool), typeof(TabItemWrapper), new PropertyMetadata(false));

            public TabItemWrapper(TabItem source)
            {
                Binding b = new Binding("IsSelected");
                b.Source = this;
                b.Mode = BindingMode.TwoWay;
                source.SetBinding(TabItem.IsSelectedProperty, b);
            }
        }
    }
}

在这个转换器中,我将标签项的IsSelected绑定到包装类的属性,并用它在视图中绑定

注意:此转换器仅适用于静态选项卡项,如果您打算在运行时添加或删除选项卡项,则可能需要处理CollectionChanged事件以使结果保持同步。

结果

result