2017-01-31 2 views
1

Ich schrieb ein CustomControl, das direkte Inhalte unterstützt. Wenn ich ein TabControl darin neste, wird beim Start kein Tab-Element ausgewählt. Es passiert nur, wenn ItemsSource verwendet wird. Wer weiß, was los ist?TabControl in CustomControl lädt ohne ausgewählten Tab-Eintrag

enter image description here

Beispielimplementierung

In 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)); 
} 

In 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

Ersetzen Sie in Ihrem Style für CustomControl1 Ihren ContentPresenter durch ein ContentControl und legen Sie die Content-Eigenschaft manuell fest. –

+0

Guter Gedanke, aber dasselbe Verhalten mit ContentControl. – Vimes

Antwort

2

Nach einiger Zeit der Stochern habe ich eine Lösung gefunden, aber ich bin die genauen Gründe für dieses Verhalten nicht sicher.

Ich habe Ihr Beispiel geändert und das Verhalten verglichen, wenn die TabControl in eine ContentControl und eine CustomControl1 gebracht wurde. Wie vorauszusehen war, wurde die erste Registerkarte im Fall von ContentControl ausgewählt, aber im Fall von CustomControl1 war dies nicht der Fall. Nach der Überprüfung der ContentControl source code (insbesondere der ContentControl.OnContentChanged-Methode) können wir sehen, dass es seinen Inhalt als sein logisches Kind setzt.

Ich habe dann bestätigt, dass die Einstellung der TabControl als CustomControl1 's logische Kind macht den Trick (aber ich bin mir nicht sicher, warum, wie ich schon erwähnte). So ist die minimale Lösung für Ihr Problem ist die logische Beziehung zwischen Kontrolle und dessen Inhalt im Eigentum geändertenen Rückruf zu handhaben, zB:

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); 
} 

Beachten Sie aber, dass dies einige Prüfungen fehlt (zB wenn neuer Wert bereits hat eine logisches Elternteil oder das Steuerelement ist ein Teil einer Vorlage), also möchten Sie vielleicht einfach den Code aus der referenzierten Quelle kopieren, oder Fallback, um Ihr Steuerelement von ContentControl zusammen abzuleiten.

+0

Ah, schön! Das macht den Trick. Ich habe nicht bemerkt, dass ich für CustomControl den logischen Baum verwalten muss (und TabControl davon abhängt). Zeit, mehr zu lesen. Danke fürs Graben! – Vimes