Benutzer mit den meisten Antworten
WPF, ControlTemplate, Fill im Path über DataBinding setzen

Frage
-
Hallo Forum,
ich möchte ein CustomControl (PictureBox) mit einem ControlTemplate erstellen,
bei dem die Foreground-Color dynamisch gesetzt werden kann.Dazu will ich die Fill-Color im Pfad des ControlTemplates dynamisch zur Laufzeit setzen, am besten mit DataBinding über eine DependencyProperty.
Aktuell ist die Fill-Color der PictureBox im Path jetzt so und wird auch richtig dargestellt:
<Path Data="M124.344,245....." Fill="Gray"/> // die PictureBox zeigt das Image und die graue Füllfarbe an!Ich hätte es gerne so, klappt aber nicht!
<Path Data="M124.344,245....." Fill="{Binding ASCPBFillColor}"/> // die PictureBox zeigt das Image und immer noch die graue Füllfarbe an, obwohl im CustomControl die Farbe auf blau gesetzt ist!In Stackoverflow habe ich etwas (sehr kompliziertes) dazu gefunden, was zwar funktioniert, aber ich wüßte doch gerne wieso überhaupt :-)
Nachfolgend hab ich mal meinen Code aufgelistet:// so sieht der Style und das ControlTemplate fuer meine PictureBox "ASCPictureBox" aus! <Style x:Key="StyleGasRelease" TargetType="{x:Type local:ASCPictureBox}"> <Setter Property="Foreground" Value="{Binding ASCPBFillColor}"/> // das Binding hat hier überhaupt keine Wirkung! <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:ASCPictureBox}"> <Grid> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <Canvas x:Name="GasCabinet" Height="40" UseLayoutRounding="False" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0.083,0,0,0"> <Path Data="M124.344,245....." Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type local:ASCPictureBox}}}"/> ... ... ...
// so sieht das CustomControl "ASCPictureBox" aus! public class ASCPictureBox : VisiWin.Controls.PictureBox { public SolidColorBrush ASCPBFillColor { get { return (SolidColorBrush)GetValue(ASCPBFillColorProperty); } set { SetValue(ASCPBFillColorProperty, value); } } // Using a DependencyProperty as the backing store for ASCPBFillColor. This enables animation, styling, binding, etc... public static readonly DependencyProperty ASCPBFillColorProperty = DependencyProperty.Register("ASCPBFillColor", typeof(SolidColorBrush), typeof(ASCPictureBox), new PropertyMetadata(PropertyChangedCallback)); static ASCPictureBox() { DefaultStyleKeyProperty.OverrideMetadata(typeof(ASCPictureBox), new FrameworkPropertyMetadata(typeof (ASCPictureBox))); } public override void OnApplyTemplate() { ASCPBFillColor = new SolidColorBrush(Color.FromArgb(255, 0, 0, 255)); // i.e. "blue" base.OnApplyTemplate(); } private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var ascPBBox = (ASCPictureBox)d; ascPBBox.Foreground = ascPBBox.ASCPBFillColor; } }
// so sieht die Verwendung des CustomControls "ASCPictureBox" dann in einem Window aus!
<CustomControls:ASCPictureBox HorizontalAlignment="Left" Margin="433,198,0,0" VerticalAlignment="Top" Width="53" Height="60" Style="{StaticResource StyleGasRelease}"/>
Meine Fragen:
1. Wie kann ich die Foreground-Color der PictureBox, also Fill="{Binding xyz}" in einem Path eines ControlTemplates dynamisch hinbekommen?
2. Wieso wird in meinem Beispiel die DP-Variable "ASCPBFillColor" überhaupt nicht verwendet/beachtet und es muß stattdessen im Code die Foreground-Color gesetzt werden
(ascPBBox.Foreground = ascPBBox.ASCPBFillColor)?Vielen Dank für Hinweise und Tipps im Voraus!
Gruß, mymadeus.
Antworten
-
Hallo,
zu 1.)
wenn du ein normales Binding verwendest weiß die Runtime nicht wo es nach der Eigenschaft suchen soll. Die Lösung mit dem RelativeSource sagt nur aus, dass an das erste gefundene Element von dem angegebenen Typ gebunden werden soll. Da der Typ auf ASCPictureBox festgelegt ist, wird an das Control selbst gebunden.Eigentlich verwendet man für so etwas das TemplateBinding, denn dann weiß auch die Runtime, dass die Eigenschaft im Typ des Controls, für das das Template ist, steckt. Das hast du auch schon in deinem Code verwendet, siehe Background, BorderBrush, etc.
zu 2.)
Hier verstehe ich nicht genau was du meinst. Das eigentliche Problem ist unter 1. geklärt. Entsprechend erhält dann der Pfad die Farbe die du dem Control im XMAL oder Codebehind zuweist. Deinen Codeschnipsel verstehe ich auch nicht.Tom Lambert - .NET (C#) MVP
Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets- Als Antwort markiert myamadeus Mittwoch, 20. April 2016 08:34
-
Hallo,
den Standardwert einer Dependency Property setzt du innerhalb der Deklaration.
public static readonly DependencyProperty ASCPBFillColorProperty = DependencyProperty.Register("ASCPBFillColor", typeof(SolidColorBrush), typeof(ASCPictureBox), new PropertyMetadata(DefaultValue, PropertyChangedCallback))
Diesen Wert kannst du nun im Style per Setter überschreiben, wie von dir gezeigt. Das sind erstmal die Vorraussetzungen.
Wenn du nun von außen die ASCPBFillColor-Eigenschaft des Controls setzt, wird bei einer funktionierenden Bindung auch die Farbe des Paths im Template angepasst. Das ist nun das selbe wie wenn du bei einem Button die Content-Eigenschaft zuweist. Der zugewiesene Wert wird dort auch ins Template übernommen.
In OnApplyTemplate musst du hierfür eigentlich nichts machen.
Was mich verwirrt ist, dass du Foreground mit dem Wert aus ASCPBFillColor des selben Controls befüllst. Und das Control hast du in einer Variablen liegen, das wirst du also vermutlich nicht innerhalb des Codes des Controls selbst machen. Das wird also vermutlich in einer anderen OnApplyTemplate Methode geschehen. Allerdings solltest du die Foreground-Farbe eher im XAML (ggf. per Binding) oder im Codebehind zuweisen. Von wo aus das geschieht ist dem Template egal. Wenn es korrekt ist holt es sich die Farbe aus der Dependency Property.
Tom Lambert - .NET (C#) MVP
Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets- Als Antwort markiert myamadeus Mittwoch, 20. April 2016 08:34
Alle Antworten
-
Hallo,
zu 1.)
wenn du ein normales Binding verwendest weiß die Runtime nicht wo es nach der Eigenschaft suchen soll. Die Lösung mit dem RelativeSource sagt nur aus, dass an das erste gefundene Element von dem angegebenen Typ gebunden werden soll. Da der Typ auf ASCPictureBox festgelegt ist, wird an das Control selbst gebunden.Eigentlich verwendet man für so etwas das TemplateBinding, denn dann weiß auch die Runtime, dass die Eigenschaft im Typ des Controls, für das das Template ist, steckt. Das hast du auch schon in deinem Code verwendet, siehe Background, BorderBrush, etc.
zu 2.)
Hier verstehe ich nicht genau was du meinst. Das eigentliche Problem ist unter 1. geklärt. Entsprechend erhält dann der Pfad die Farbe die du dem Control im XMAL oder Codebehind zuweist. Deinen Codeschnipsel verstehe ich auch nicht.Tom Lambert - .NET (C#) MVP
Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets- Als Antwort markiert myamadeus Mittwoch, 20. April 2016 08:34
-
Hallo Tom,
vielen Dank für die Antwort!
ok, zu Deinen Antworten:
>zu 2.)
>Hier verstehe ich nicht genau was du meinst. Das eigentliche Problem ist unter 1. geklärt.Ich möchte die Füllfarbe des Pfades für die PictureBox dynamisch setzen. Im CustomControl wird die
Property "ASCPBFillColor" von einer SPS-Variablen zur Laufzeit gesetzt (das tut hier aber nichts zur Sache).
Wenn ich das "OnApplyTemplate()"
und diese Zuweisung
ascPBBox.Foreground = ascPBBox.ASCPBFillColor;
im CustomControl.cs-File weglasse, dann bleibt die Füllfarbe der PictureBox schwarz und nicht blau.
Also wo soll ich die ASCPBFillColor dynamisch sonst setzen?
Ich will ja im xaml-Code nichts in der Art
Setter Property="Foreground" Value="{StaticResource Blue_Brush}"/>
machen! Ich brauche den Foreground-Value der PictureBox dynamisch und das hab ich leider noch nicht verstanden, wo und wie man es am besten macht!
Vielleicht ist mein Problem jetzt besser rübergekommen.
GRuß, myamadeus.
-
Hallo,
den Standardwert einer Dependency Property setzt du innerhalb der Deklaration.
public static readonly DependencyProperty ASCPBFillColorProperty = DependencyProperty.Register("ASCPBFillColor", typeof(SolidColorBrush), typeof(ASCPictureBox), new PropertyMetadata(DefaultValue, PropertyChangedCallback))
Diesen Wert kannst du nun im Style per Setter überschreiben, wie von dir gezeigt. Das sind erstmal die Vorraussetzungen.
Wenn du nun von außen die ASCPBFillColor-Eigenschaft des Controls setzt, wird bei einer funktionierenden Bindung auch die Farbe des Paths im Template angepasst. Das ist nun das selbe wie wenn du bei einem Button die Content-Eigenschaft zuweist. Der zugewiesene Wert wird dort auch ins Template übernommen.
In OnApplyTemplate musst du hierfür eigentlich nichts machen.
Was mich verwirrt ist, dass du Foreground mit dem Wert aus ASCPBFillColor des selben Controls befüllst. Und das Control hast du in einer Variablen liegen, das wirst du also vermutlich nicht innerhalb des Codes des Controls selbst machen. Das wird also vermutlich in einer anderen OnApplyTemplate Methode geschehen. Allerdings solltest du die Foreground-Farbe eher im XAML (ggf. per Binding) oder im Codebehind zuweisen. Von wo aus das geschieht ist dem Template egal. Wenn es korrekt ist holt es sich die Farbe aus der Dependency Property.
Tom Lambert - .NET (C#) MVP
Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets- Als Antwort markiert myamadeus Mittwoch, 20. April 2016 08:34
-
Hallo Forum nochmal,
ich glaube jetzt klappt es wie gewünscht!
Ich muß als Property im Setter natürlich meine dynamische Füllfarben-Variable "ASCPBFillColor" und nicht
Foreground angeben!
<Style x:Key="StyleGasRelease" TargetType="{x:Type local:ASCPictureBox}"> <Setter Property="ASCPBFillColor" Value="Blue"/>
<Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:ASCPictureBox}"> <Grid> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <Canvas x:Name="GasCabinet" Height="40" UseLayoutRounding="False" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0.083,0,0,0"> <Path Data="M124.344,245....." Fill="{Binding Path=ASCPBFillColor, RelativeSource={RelativeSource AncestorType={x:Type local:ASCPictureBox}}}"/> ... ... ...
ZUr Laufzeit kann ich dann im CustomControl.cs file die Farbe setzen wie gewünscht. Genau das wollte
ich. Ist halt schwer zu formulieren für einen WPF-Beginner, wenn man die WPF nicht gut kennt!
Danke und Gruß, mymadeus.
-
Hallo Tom,
sorry, hatte Deine neue Antwort nicht rechtzeitig gesehen.
Ja, Du hast natürlich recht, den Foreground muß man dann nicht setzen (weder im OnApply noch im PropertyChangeCallback), wenn das Binding
auf die Property richtig funktioniert, so wie es jetzt schön geht.
Ich danke Dir nochmals für Deine Hilfe in diesem Fall.
Also WPF ist nicht gerade schnell zu erlernen sowie damals "WinForms".
Ist noch ein weiter Weg, werde hier bestimmt noch häufiger vorstellig werden!
Danke und Gruß, myamadeus.