2016-04-27 9 views
0

Hallo, ich versuche, ein benutzerdefiniertes TabItem mit löschen Button zu erstellen, ich möchte meinen Viewmodel-Befehl an meine benutzerdefinierte Dependency-Eigenschaft 'DeleteCommandProperty' binden. Kann mir jemand sagen, was ich falsch mache?WPF-Custom TabItem mit Delete Button Binding Problem

meine Gewohnheit TabControl:

/// <summary> 
    /// TabControl withCustom TabItem 
    /// </summary> 
    public class MyTabControl:TabControl 
    { 
     /// <summary> 
     /// TabItem override 
     /// </summary> 
     /// <returns></returns> 
     protected override DependencyObject GetContainerForItemOverride() 
     { 
      return new MyTabItem(); 
     } 
    } 

meine Gewohnheit TabItem Klasse:

/// <summary> 
    /// Custom TabItem 
    /// </summary> 
    public class MyTabItem:TabItem 
    { 
     /// <summary> 
     /// Delete Command 
     /// </summary> 
     public static DependencyProperty DeleteCommandProperty = DependencyProperty.Register(
      "DeleteCommand",typeof(ICommand),typeof(MyTabItem)); 

     /// <summary> 
     /// Delete 
     /// </summary> 
     public ICommand DeleteCommand 
     { 
      get { return (ICommand)GetValue(DeleteCommandProperty); } 
      set { SetValue(DeleteCommandProperty, value); } 
     } 
    } 

wenn ich binden den DeleteCommand direkt wie dieses mein Kommando in meinem Ansichtsmodell ausgeführt wird

<customControls:MyTabControl> 
      <customControls:MyTabItem Header="Test" DeleteCommand="{Binding DeleteStudiengangCommand}" Template="{DynamicResource MyTabItemControlTemplate}"/> 
     </customControls:MyTabControl> 

bu wenn versuchen, den deleteCommand per Stil wie folgt zu binden, aber es funktioniert nicht:

<Style TargetType="customControls:MyTabItem"> 
         <Setter Property="Template" Value="{DynamicResource MyTabItemControlTemplate}"/> 
         <Setter Property="DeleteCommand" Value="{Binding MyDeleteCommand}"/> 
        </Style> 



<customControls:MyTabControl ItemsSource="{Binding MyList}" SelectedItem="{Binding SelectedItem}" SelectedIndex="0"> 
        <customControls:MyTabControl.ContentTemplate> 
         <DataTemplate> 
          <ItemsControl ItemsSource="{Binding Value}" > 
           <ItemsControl.ItemsPanel> 
            <ItemsPanelTemplate> 
             <WrapPanel/> 
            </ItemsPanelTemplate> 
           </ItemsControl.ItemsPanel> 
          </ItemsControl> 
         </DataTemplate> 
        </customControls:MyTabControl.ContentTemplate> 
       </customControls:MyTabControl> 
+0

Sie können dies auf [MVCE] reduzieren (http://stackoverflow.com/help/mcve). Versuchen Sie beispielsweise nicht, den 'DeleteCommand' in Ihrem Stil zu binden, es sei denn, es ist wichtig, Ihr Problem zu zeigen ... Weisen Sie stattdessen einen statischen Befehl in Ihrem Konstruktor – grek40

+0

Ich sehe Sie Ihre Frage irgendwie bearbeitet, aber es ist sehr weit von ** minimal ** (Sie verwenden weit zu viele Vorlagen, die nicht mit Ihrem Problem zusammenhängen), weit davon entfernt, ** verifizierbar ** zu sein (Ich baute ein kleines Beispiel mit Ihrem style-basierten Befehlssatz und es funktionierte gut), weit aus ** complete ** (wo ist der Code für 'customControls: MyTabControl'? auch, bitte zwing mich nicht, Blend zu verwenden) und du erklärst nicht wirklich, was das beobachtete Verhalten im Gegensatz zu dem erwarteten Verhalten ist, Also ist auch kein ** Beispiel ** angegeben. – grek40

+0

Ich habe meine TabControl-Klasse hinzugefügt und versuche zu erklären, was nicht funktioniert habe hoffe, dass jemand helfen kann – Johannes

Antwort

2

TL; DR

Ich vermute, Ihre DataContext von MyList Ihr aktuelles Element enthält (was auch immer es ist), so dass der Stil Setter kann nicht auf die MyDeleteCommand Eigenschaft als Sie geplant. Sehen Sie sich das Visual Studio Debugger-Protokoll an, ob dort eine verbindliche Ausnahme protokolliert wird.


Beispiel, die von einem funktionierenden Code entwickelt, bis es ein mögliches Problem Erklärung offenbaren passiert ist.

Es scheint einige Schwierigkeiten haben, Ihr Beispiel bei der Reduzierung, so das einzige, was ich kann Ihnen auf die Informationen, die Sie bieten auf Basis ist ein kleines Arbeitsbeispiel mit dem Style und TemplateBinding Ansatz, die Sie als Basis verwenden können, zu identifizieren dein echtes Problem. Bearbeiten: Die Erklärung am Ende könnte tatsächlich die Antwort auf Ihre Frage sein.

Hinweis: Möglicherweise müssen Sie die Namespaces ändern, damit sie mit Ihrer Projektkonfiguration übereinstimmen.

MainWindow.xaml

<Window x:Class="WpfApplication2.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:WpfApplication2" 
     Title="MainWindow" Height="350" Width="525" 
     Loaded="Window_Loaded"> 

    <Window.Resources> 
     <!-- Header template --> 
     <ControlTemplate x:Key="MyTabItemControlTemplate" TargetType="{x:Type local:MyTabItem}"> 
      <!-- Some text and the command button with template binding --> 
      <StackPanel Orientation="Horizontal" Background="Aquamarine" Margin="3"> 
       <ContentPresenter Content="{TemplateBinding Header}" VerticalAlignment="Center" Margin="2"/> 
       <Button Content="Delete" Command="{TemplateBinding DeleteCommand}" Margin="2"/> 
      </StackPanel> 
     </ControlTemplate> 

     <!-- Setting the control template and assigning the command implementation --> 
     <Style TargetType="{x:Type local:MyTabItem}"> 
      <Setter Property="Template" Value="{DynamicResource MyTabItemControlTemplate}"/> 
      <Setter Property="DeleteCommand" Value="{Binding MyDeleteCommand}"/> 
      <Setter Property="Header" Value="Default Header Text"/> 
     </Style> 
    </Window.Resources> 

    <Grid> 
     <local:MyTabControl ItemsSource="{Binding MyTabItemList}"/> 
    </Grid> 
</Window> 

MainWindow.xaml.cs

/// <summary> 
/// TabControl withCustom TabItem 
/// </summary> 
public class MyTabControl : TabControl 
{ 
    /// <summary> 
    /// TabItem override 
    /// </summary> 
    protected override DependencyObject GetContainerForItemOverride() 
    { 
     return new MyTabItem(); 
    } 
} 

public class MyTabItem : TabItem 
{ 
    /// <summary> 
    /// Delete Command 
    /// </summary> 
    public static DependencyProperty DeleteCommandProperty = DependencyProperty.Register(
     "DeleteCommand", typeof(ICommand), typeof(MyTabItem)); 

    /// <summary> 
    /// Delete 
    /// </summary> 
    public ICommand DeleteCommand 
    { 
     get { return (ICommand)GetValue(DeleteCommandProperty); } 
     set { SetValue(DeleteCommandProperty, value); } 
    } 
} 

public class MyCommand : ICommand 
{ 
    public void Execute(object parameter) 
    { 
     MessageBox.Show("Hello WPF", "Message"); 
    } 

    public bool CanExecute(object parameter) 
    { 
     return true; 
    } 

    public event EventHandler CanExecuteChanged { add { } remove { } } 
} 

public class MyContext 
{ 
    public ICommand MyDeleteCommand { get; set; } 

    public List<object> MyTabItemList { get; set; } 
} 

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     var list = new List<object>(); 
     list.Add(new TextBlock() { Text = "Test 1" }); 
     list.Add(new MyTabItem() { Content = "Test Content 2", Header = "Test Header 2" }); 
     list.Add(new TabItem() { Content = "Test Content 3", Header = "Test Header 3" }); 
     this.DataContext = new MyContext() 
     { 
      MyTabItemList = list, 
      MyDeleteCommand = new MyCommand() 
     }; 
    } 
} 

Zusammenfassung des Beispiels: Sie sehen drei verschiedene Registerkarten, die jeweils mit ihrem einzigartigen Aufbau und Aussehen:

  1. Der Registerkarteneintrag wird aus der GetContainerForItemOverride-Methode erstellt. Der Stilausrichter für die Eigenschaft Header gibt den Text an, der in der Kopfzeile angezeigt wird. Die MyDeleteCommand Bindung funktioniert nicht!
  2. Der Tab-Eintrag wird als MyTabItem mit Header und Inhaltswert bereitgestellt. Der Style-Setter für die Header-Eigenschaft gilt nicht, da die Eigenschaft explizit festgelegt ist. Der Stilsetzer für die DeleteCommand-Eigenschaft bindet die MyDeleteCommand-Eigenschaft von .
  3. Das Registerelement wird als TabItem bereitgestellt, und da es keine Außerkraftsetzung von MyTabControl.IsItemItsOwnContainerOverride gibt, wird dies als Steuerelement von MyTabControl akzeptiert. Die gesamte Vorlage MyTabItem gilt nicht.

Die Ausgabe Debuggen in Visual Studio gibt einen Hinweis auf das zugrunde liegende Problem für das erste Element tab:

System.Windows.Data Error: 40 : BindingExpression path error: 'MyDeleteCommand' property not found on 'object' ''TextBlock' (Name='')'. BindingExpression:Path=MyDeleteCommand; DataItem='TextBlock' (Name=''); target element is 'MyTabItem' (Name=''); target property is 'DeleteCommand' (type 'ICommand')

Der Grund dafür ist, dass der aktuelle Registerkarte Elementinhalt die neuen lokalen DataContext in diesem Szenario wird Im Gegensatz zum zweiten Tab-Element, bei dem das Objekt selbst als Container akzeptiert wird.

könnte eine Lösung sein Nutzung des Propper Kontext binden den Befehl, um sicherzustellen:

Vermeintliche Sie einige geeignete Eltern-Element einen Namen geben x:Name="_this", dann können Sie DataContext die Eltern zugreifen.

<Setter Property="DeleteCommand" Value="{Binding DataContext.MyDeleteCommand,ElementName=_this}"/> 
+0

Danke, dass du den DataContext spezifizierst, wie du gesagt hast, löste das Problem. – Johannes