2016-04-06 18 views
6

Ich möchte ein UserControl erstellen (in diesem Fall ein Rechteck-Button mit definierten Hintergrundfarben), welches eigenen Inhalt hosten kann.Wie benutze ich einen ContentPresenter in einem UserControl?

Usercontrol:

<UserControl x:Class="SGDB.UI.Controls.ModernButton" 
     xmlns:local="clr-namespace:SGDB.UI.Controls" 
     xmlns:converter="clr-namespace:SGDB.UI.Converter" 
     x:Name="_modernButton"> 
<Button> 
    <Button.Resources> 
     <converter:EnumToColorConverter x:Key="ColorConverter"/> 
    </Button.Resources> 
    <Button.Template> 
     <ControlTemplate> 
      <Border Width="{Binding Size, ElementName=_modernButton}" Height="{Binding Size, ElementName=_modernButton}" BorderBrush="Black" BorderThickness="0.8,0.8,3,3"> 
       <Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}"> 
        <ContentPresenter/> 
       </Grid> 
      </Border> 
     </ControlTemplate> 
    </Button.Template> 
</Button> 

Nun, wie Sie es erwarten kann, wenn ich diese Kontrolle in meinem Mainview verwenden Everthing ganz gut funktioniert, bis ich einige Inhalt definieren.

Verwendung:

<control:ModernButton Size="200" BackgroundColor="Light"> 
    TEST 
</control:ModernButton> 

In diesem Fall "TEST" wird den gesamten Inhalt des Usercontrol (die gesamte Knopf-Schablone) außer Kraft setzen. Ich schätze, das passiert, weil der Button im UserControl selbst als "Content" definiert ist und beim Definieren eines neuen Inhalts überschrieben wird.

Die letzte Frage ist also: Ist es möglich zu erreichen, was ich suche? wenn ja: Wie? Wie kann ich den Inhalt, den ich in meiner Hauptansicht definiere, in den selbstdefinierten ContentPresenter in meiner Button-Vorlage statt in den ContentPresenter der UserControls umleiten?

Wenn möglich, möchte ich nicht eine neue dp-propery zu schaffen, die meine Inhalte hostet, zB:

<controls:MordernButton Size="200" BackgroundColor="Light"> 
    <controls:ModernButton.Content> 
     I don't want this, if possible 
    </controls:ModernButton.Content> 
</controls:ModernButton> 
+0

Sie meinen, Sie wollen nicht neue dp dafür erstellen? – Gopichandar

+0

Korrekt - wenn möglich, natürlich. – C4p741nZ

+0

@ Chill-X Siehe meine Antwort unten. Lassen Sie mich wissen, wenn Sie irgendwelche Probleme haben. – Gopichandar

Antwort

5

hier alles setzen wir gehen.

<UserControl x:Class="SGDB.UI.Controls.ModernButton" 
    xmlns:local="clr-namespace:SGDB.UI.Controls" 
    xmlns:converter="clr-namespace:SGDB.UI.Converter" 
    x:Name="_modernButton"> 

    <UserControl.Template> 
     <ControlTemplate TargetType="UserControl"> 
      <Button Content="{TemplateBinding Content}"> 
       <Button.Resources> 
        <converter:EnumToColorConverter x:Key="ColorConverter"/> 
        </Button.Resources> 
      <Button.Template > 
       <ControlTemplate TargetType="Button"> 
        <Border Width="{Binding Size, 
            ElementName=_modernButton}" 
        Height="{Binding Size, 
            ElementName=_modernButton}" 
        BorderBrush="Black" 
        BorderThickness="0.8,0.8,3,3"> 
         <Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}"> 
          <ContentPresenter /> 
         </Grid> 
        </Border> 
       </ControlTemplate> 
      </Button.Template> 
      </Button> 
     </ControlTemplate> 
    </UserControl.Template> 
</UserControl> 
+0

Zuerst schien es sehr gut - aber wenn man etwas Inhalt ("TEST" oder ) übergibt, zeigt sich nichts Die Kontrolle bleibt leer (außer der eigenen Farbe) – C4p741nZ

+0

Das war's - könnten Sie erklären, warum der TargetType des Buttons einen so großen Einfluss auf den ContentPresenter hatte? Und wenn du dabei bist, könntest du vielleicht erklären, warum die Templatebinding-Funktion des Buttons WPF daran hindert, den gesamten Inhalt zu löschen, wenn er Inhalte in ein Control übergibt? Vielen Dank im Voraus :) – C4p741nZ

+1

Das wird ein großes Thema sein. Kann sein [http://stackoverflow.com/a/3632926/2819451] beantwortet Ihre erste Frage. – Gopichandar

2

Nehmen wir an, dass youre Usercontrol ist:

<UserControl x:Class="QuickAndDirtyAttempt.Decorator" .... 
     <UserControl.Template> 
     <ControlTemplate TargetType="{x:Type local:Decorator}"> 
      <StackPanel Orientation="Vertical"> 
      <Label>Foo</Label> 
      <ContentPresenter/> 
      <Label>Bar</Label> 
      </StackPanel> 
     </ControlTemplate> 
     </UserControl.Template> 
</UserControl> 

Notiere die Targettype-Eigenschaft auf der Vorlage: Ohne sie wird das Projekt glücklich kompilieren, aber der ContentPresenter wird nicht funktionieren. Und dann:

<Window ... > 
    <StackPanel Orientation="Vertical"> 
     <local:Decorator> 
      <Label Background="Wheat">User supplied content here</Label> 
     </local:Decorator> 
    </StackPanel> 
</Window> 

Ich empfehle Ihnen dringend, read this vor

+0

Ich lese das aber über den Teil lesen, der sagt: "Ohne den TargetType wird das Projekt gerne kompilieren, aber der ContentPresenter wird nicht funktionieren". Sie verdienen meine Erwiderung, weil das CodeProject erklärt, warum man meine Lösung nicht verwenden sollte :) – C4p741nZ

2

Einfach; Umgehe und ersetze einfach die Vorlage des UserControls.

<UserControl.Template> 
     <ControlTemplate TargetType="{x:Type UserControl}"> 
      <Button Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"> 
       <Button.Resources> 
        <converter:EnumToColorConverter x:Key="ColorConverter"/> 
       </Button.Resources> 
       <Button.Template> 
        <ControlTemplate TargetType="{x:Type Button}"> 
         <Border Width="{Binding Size, 
             ElementName=_modernButton}" 
         Height="{Binding Size, 
             ElementName=_modernButton}" 
         BorderBrush="Black" 
         BorderThickness="0.8,0.8,3,3"> 
          <Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}"> 
           <ContentPresenter /> 
          </Grid> 
         </Border> 
        </ControlTemplate> 
       </Button.Template> 
      </Button> 
     </ControlTemplate> 
    </UserControl.Template> 

a Alle Benutzersteuerung (zumindest hinsichtlich der XAML und deren Vorlage), ist eine Grenze mit einem Content seines Innern. Der ContentPresenter ist wirklich der einzige wichtige Teil.

Also alles, was Sie tun, ist seine Vorlage aus und feed die Content-Eigenschaft der UserControl hat in etwas ein wenig anders; In diesem Fall, deine Taste.

Dies ist der Unterschied zwischen einem Benutzersteuerelement macht aus anderen Kontrollen und einige Steuerelemente in ein Benutzersteuer schiebend. Wenn Sie die Benutzersteuerung aus anderen Steuerelementen herausnehmen, erhalten Sie viel mehr Leistung.

+1

Denke, das könnte auch funktionieren, wenn der Typ der zweiten ControlTemplate "Button" wäre. – C4p741nZ

+0

Oh ja, wie habe ich das vermisst? - Editiert es in. – Logan

10

Verwenden Sie die ContentPropertyAttribute, um den XAML anzuweisen, diese Eigenschaft anstelle der eigentlichen Content-Eigenschaft festzulegen.

Dann binden Sie in Ihrem XAML den Content Presenter an die InnerContent-Eigenschaft.

<ContentPresenter Content="{Binding InnerContent, ElementName=_modernButton}"/> 

Auf diese Weise können Sie Folgendes tun, ohne den eigentlichen Inhalt zu ersetzen.

<control:ModernButton Size="200" BackgroundColor="Light"> 
    TEST 
</control:ModernButton> 
+2

Funktioniert auch. Aber ich wollte wissen, wie die Dinge in XAML funktionieren - ich mag es wirklich nicht, Code mit Attributen zu dekorieren. – C4p741nZ

+0

Super Tipp! Da es sich nicht um eine Template-Überschreibung handelt, können Sie Namen und Links mit Code einfach hinterlegen –