我的应用程序中有1 ... n个tabcontrols,具有以下XAML设置:
<TabControl Name="ordersTabControl" ItemsSource="{Binding CoilItems}">
<TabControl.ItemTemplate>
<DataTemplate DataType="models:Coil">
<StackPanel>
<TextBlock Text="{Binding CoilCode, StringFormat='Coil: {0}'}" />
<TextBlock Text="{Binding ArticleCode, StringFormat='Auftrag: {0}'}" />
<TextBlock Text="{Binding RestWeight, StringFormat='Restgewicht: {0} kg'}" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
[...]
</TabControl.ContentTemplate>
</TabControl>
打开的标签数量在运行时更改。现在我想在每个标签中显示一个索引(即第一个标签显示“订单1”,第二个“订单2”等等)以及每个标题中已有的信息。
使用DataTemplate时的AFAIK我无法通过代码隐藏访问tab-properties,所以XAML中是否有任何方法可以在tabheader中绑定文本块以显示tabcontrol中该特定选项卡的索引?
我认为应该可以使用RelativeSource和FindAncestors吗?唉,我真的找不到关于这些设置的任何明确的教程(我2天前才开始使用WPF)。
答案 0 :(得分:2)
我将使用附加属性为您提供解决方案。检查代码:
附加属性
public static class IndexAttachedProperty
{
#region TabItemIndex
public static int GetTabItemIndex(DependencyObject obj)
{
return (int) obj.GetValue(TabItemIndexProperty);
}
public static void SetTabItemIndex(DependencyObject obj, int value)
{
obj.SetValue(TabItemIndexProperty, value);
}
// Using a DependencyProperty as the backing store for TabItemIndex. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TabItemIndexProperty =
DependencyProperty.RegisterAttached("TabItemIndex", typeof (int), typeof (IndexAttachedProperty),
new PropertyMetadata(-1));
#endregion
#region TrackTabItemIndex
public static bool GetTrackTabItemIndex(DependencyObject obj)
{
return (bool) obj.GetValue(TrackTabItemIndexProperty);
}
public static void SetTrackTabItemIndex(DependencyObject obj, bool value)
{
obj.SetValue(TrackTabItemIndexProperty, value);
}
// Using a DependencyProperty as the backing store for TrackTabItemIndex. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TrackTabItemIndexProperty =
DependencyProperty.RegisterAttached("TrackTabItemIndex", typeof (bool), typeof (IndexAttachedProperty),
new PropertyMetadata(false, TrackTabItemIndexOnPropertyChanged));
private static void TrackTabItemIndexOnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var tabControl = GetParent(d, p => p is TabControl) as TabControl;
var tabItem = GetParent(d, p => p is TabItem) as TabItem;
if (tabControl == null || tabItem == null)
return;
if (!(bool)e.NewValue)
return;
int index = tabControl.Items.IndexOf(tabItem.DataContext == null ? tabItem : tabItem.DataContext);
SetTabItemIndex(d, index);
}
#endregion
public static DependencyObject GetParent(DependencyObject item, Func<DependencyObject, bool> condition)
{
if (item == null)
return null;
return condition(item) ? item : GetParent(VisualTreeHelper.GetParent(item), condition);
}
}
此代码定义了两个附加属性,第一个是设置项是否跟踪包含它的选项卡项索引。第二个是索引属性。
XAML示例代码:
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type WpfApplication3:A}">
<StackPanel x:Name="tabItemRoot" WpfApplication3:IndexAttachedProperty.TrackTabItemIndex ="True">
<TextBlock Text="{Binding Text}"/>
<TextBlock Text="{Binding Path=(WpfApplication3:IndexAttachedProperty.TabItemIndex), ElementName=tabItemRoot}"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
上面的代码是使用附加属性的示例。您可以轻松地适应您的代码。
<强>结果:强>
希望此代码适合您...
答案 1 :(得分:2)
如果您没有将AlternationCount
属性用于其他目的,可以通过破解它来获得更简单的解决方案。
像这样绑定AlternationCount
<TabControl AlternationCount="{Binding Path=Items.Count, RelativeSource={RelativeSource Self}}">
然后在你的ItemTemplate中将你想要的TextBlock或其他控件绑定到AlternationIndex
,
<TextBlock Text="{Binding Path=(ItemsControl.AlternationIndex), RelativeSource={RelativeSource FindAncestor, AncestorType=TabItem}}" />
将自定义转换器插入上述绑定后,您可以显示任何内容。
答案 2 :(得分:1)
即使你只能访问代码隐藏中的TabItem
属性,它也无济于事,因为标签在TabControl
集合中不知道它自己的索引。所有ItemsControls
都是如此,看起来很烦人,但这是有道理的,因为什么时候任何对象都能告诉你它在集合中的位置是什么?
只要您可以访问控件的ItemsCollection
和选项卡的内容,就可以使用IndexOf来完成。我们可以在MultiValueConverter
中执行此操作,以便可以在DataTemplate中完成。
转换代码:
public class ItemsControlIndexConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ItemCollection itemCollection = (ItemCollection)values[0];
return (itemCollection.IndexOf(values[1]) + 1).ToString();
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
TabControl XAML:
<TabControl ItemsSource="{Binding CoilItems}">
<TabControl.Resources>
<local:ItemsControlIndexConverter x:Key="IndexConverter"/>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource IndexConverter}" StringFormat="Order {0}" Mode="OneWay">
<Binding RelativeSource="{RelativeSource AncestorType=TabControl}" Path="Items"/> <!-- First converter index is the ItemsCollection -->
<Binding /> <!-- Second index is the content of this tab -->
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<!-- Fill in the rest of the header template -->
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>