我尝试使用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
。实际上,如果我删除后者,显示屏保持不变。
答案 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
事件以使结果保持同步。
结果