我写了一个支持直接内容的CustomControl。当我在其中嵌套TabControl时,在启动时没有选择任何标签项。它只在使用ItemsSource时才会发生。谁知道什么是错的?
示例实施
在MainWindow.xaml:
<Window.DataContext>
<local:VM/>
</Window.DataContext>
<Grid Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TabControl ItemsSource="{Binding Data}"/>
<local:CustomControl1 Grid.Column="1">
<TabControl ItemsSource="{Binding Data}" />
</local:CustomControl1>
</Grid>
VM.cs
class VM
{
public List<int> Data { get; set; } = new List<int>{ 1, 2, 3, 4 };
}
CustomControl1:
[ContentProperty("Content")]
public class CustomControl1 : Control
{
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
public FrameworkElement Content
{
get { return (FrameworkElement)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register("Content", typeof(FrameworkElement), typeof(CustomControl1), new PropertyMetadata(null));
}
在Generic.xaml中:
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
答案 0 :(得分:2)
经过一段时间的探索后,我找到了一个解决方案,但我不确定这种行为背后的确切原因。
我修改了您的示例并比较了TabControl
放在ContentControl
和CustomControl1
内时的行为。可以预见,选择ContentControl
时的第一个标签,但是CustomControl1
则不是。在检查ContentControl
source code(特别是ContentControl.OnContentChanged
方法)后,我们可以看到它的作用是将其内容设置为逻辑子代。
然后我确认将TabControl
设置为CustomControl1
的逻辑子进行操作(但我不知道为什么,正如我所提到的)。因此,解决问题的最小方法是在属性更改回调中处理控件与其内容之间的逻辑关系,例如:
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(
"Content",
typeof(FrameworkElement),
typeof(CustomControl1),
new PropertyMetadata(null)
{
PropertyChangedCallback = OnContentChanged
});
private static void OnContentChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var control = (CustomControl1)d;
if (e.OldValue != null)
control.RemoveLogicalChild(e.OldValue);
if (e.NewValue != null)
control.AddLogicalChild(e.NewValue);
}
请注意,这缺少一些检查(例如,如果新值已经具有逻辑父项或控件是模板的一部分),那么您可能只想从引用的源复制代码,或者回退到派生你完全控制ContentControl
。