2017-01-31 2 views
1

私は、直接コンテンツをサポートするCustomControlを書きました。 TabControlをその中に入れ子にすると、起動時にタブ項目が選択されません。 ItemsSourceを使用している場合にのみ発生します。誰が何が間違っているのか分かりますか?CustomControl内のTabControlが選択されたタブ項目なしで読み込まれます

enter image description here

サンプル実装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:

Generic.xamlで
[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)); 
} 

<Style TargetType="{x:Type local:CustomControl1}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type local:CustomControl1}"> 
       <ContentPresenter/> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 
+0

CustomControl1のスタイルでは、ContentPresenterをContentControlに置き換え、Contentプロパティを手動で設定してみてください。 –

+0

良い考えですが、ContentControlと同じ動作です。 – Vimes

答えて

2

チャンスをうかがっのいくつかの時間後、私は解決策を見つけたが、私はこの行動の背後にある正確な理由のわかりません。

TabControlContentControlCustomControl1に入れたときの動作を比較して比較しました。予想通り、ContentControlの場合の最初のタブが選択されましたが、CustomControl1の場合はそうではありませんでした。 ContentControl source code(特にContentControl.OnContentChangedメソッド)を調べた後、その内容が論理的な子として設定されることがわかります。

CustomControl1の論理的な子としてTabControlを設定すると、そのトリックが実行されることが確認されました(ただし、私が述べた理由はわかりません)。だからあなたの問題に最小限のソリューションは、例えば、あなたのコントロールとプロパティ変更コールバック中の含有量との間の論理的な関係を処理することです:

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から派生させることができます。

+0

ああ、素敵!それはトリックです。 CustomControlについては、論理ツリー(およびTabControlはそれに依存します)を管理する必要があることを認識していませんでした。もっと読む時間。掘ってくれてありがとう! – Vimes

関連する問題