Hi,
ich habe in einer WPF-Anwendugn eine Klasse "ButtonModern" die von "Button" ableitet.
In dieser Klasse erweitere ich die Basisklasse "Button" u.a. um eine DependencyProperty "IconScale".
Den Wert aus "IconScale" möchte ich in einer RenderTransform des ContentPresenters in meinem Style verwenden und dachte zunächst ich könnte einfach mit TemplateBinding auf den Wert meiner Property zugreifen. Dies habe ich so gemacht:
<Style TargetType="Controls:ButtonModern">
<Setter Property="IconScale" Value="0.1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Controls:ButtonModern">
<Grid Background="{TemplateBinding Property=Background}">
<Grid Margin="8">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="False" RenderTransformOrigin="0.5,0.5">
<ContentPresenter.Effect>
<DropShadowEffect Opacity="0.5"/>
</ContentPresenter.Effect>
<ContentPresenter.RenderTransform>
<ScaleTransform ScaleX="{TemplateBinding Property=IconScale}" ScaleY="{TemplateBinding Property=IconScale}"/>
</ContentPresenter.RenderTransform>
</ContentPresenter>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Allerdings scheint das TemplateBinding in diesem Fall nicht zu funktionieren, da die Scale immer "1" ist.
Wende ich hingegen ein Binding mit RelativeSource TemplatedParent an funktioniert es:
<Style TargetType="Controls:ButtonModern">
<Setter Property="IconScale" Value="0.1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Controls:ButtonModern">
<Grid Background="{TemplateBinding Property=Background}">
<Grid Margin="8">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="False" RenderTransformOrigin="0.5,0.5">
<ContentPresenter.Effect>
<DropShadowEffect Opacity="0.5"/>
</ContentPresenter.Effect>
<ContentPresenter.RenderTransform>
<ScaleTransform ScaleX="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IconScale}" ScaleY="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IconScale}"/>
</ContentPresenter.RenderTransform>
</ContentPresenter>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Meine Frage ist nun warum die Variante mit dem TemplateBinding nicht funktioniert? Ich meine, bei dem umschließenden Grid funktioniert das TemplateBinding für den Background ja schließlich auch?
EDIT: was mir eben noch aufgefallen ist: obwohl das Beispiel 2 funktioniert, meldet Visual Studio beim Starten im Direktfenster den folgenden Fehler:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=IconScale; DataItem=null; target element is 'ScaleTransform' (HashCode=13842929); target property is 'ScaleX' (type 'Double')
Vielen Dank für alle Antworten im voraus,
Astrix
Kann es sein, dass du IconScale nicht korrekt initialisierst? Wenn du IconScale mit null initialisert, dann kann es zu so einer Fehlermeldung kommen. Dürfte aber nicht deinen Problem erklären.
Gruß dat Tala
Hallo Astrix,
ich bin jetzt auch noch relativ neu bei WPF, aber ich vermute mal, dass das TemplateBinding sich immer auf das unmittelbare Element bezieht, in dem es verwendet wird.
In Deinem Fall würde sich das TemplateBinding dann auf ein (nicht vorhandenes) Template für einen ContentPresenter beziehen. Aber da wird sich sicher noch jemand hier finden, der das sicherer erklären kann.
Hier hab ich einen interessanten Thread dazu gefunden: WPF TemplateBinding vs RelativeSource TemplatedParent
Speziell diese Erklärung dazu gefällt mir:
TemplateBinding - More limiting than using regular Binding
More efficient than a Binding but it has less functionality Only works inside a ControlTemplate's visual tree **Doesn't work with properties on Freezables** Doesn't work within a ControlTemplate's Trigger Provides a shortcut in setting properties(not as verbose),e.g. {TemplateBinding targetProperty}
Regular Binding - Does not have above limitations of TemplateBinding
Respects Parent Properties Resets Target Values to clear out any explicitly set values Example: <Ellipse Fill="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Background}"/>