Wie verhindert man im XAML das Overriden einer im Style definierten Property?

  • WPF MVVM
  • .NET (FX) 4.5–4.8

Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von kafffee.

    Wie verhindert man im XAML das Overriden einer im Style definierten Property?

    Hallo zusammen und ein Gutes Neues nochmal :)

    Ich hab eine ganz kurze Frage, obwohl ich fast schon vermute, dass das so im XAML nicht möglich ist:

    Wenn ich direkt im Control eine Property bereits gesetzt habe, also z.B. die Fill-Property...:

    XML-Quellcode

    1. <Path Data="xyz" Fill="White" HorizontalAlignment="Center" VerticalAlignment="Center" Width="100" Height="100" Stretch="Uniform"/>


    Kann ich die vom Style aus overriden? Also z.B.:

    XML-Quellcode

    1. <Style TargetType="{x:Type Path}">
    2. <Style.Triggers>
    3. <Trigger Property="IsMouseOver" Value="True">
    4. <Setter Property="Fill" Value="Red"/>
    5. </Trigger>
    6. <Trigger Property="IsMouseOver" Value="False">
    7. <Setter Property="Fill" Value="White"/>
    8. </Trigger>
    9. </Style.Triggers>
    10. </Style>


    Also quasi so, wie man mit CSS auch HTML overriden kann....

    Oder hat jemand eine Idee für ein Workaround, wenn ich nicht in meinem 2.126 Path Controls ( :whistling: ) überall die Definition der Fill-Property rauslöschen möchte... Ich weiss, das hätte ich mir besser vorher überlegen sollen :)

    ____________________________________________________________________________

    Edit:
    Hatte grad mal wieder einen meiner Geistesblitze. Mit einer Animation geht das:

    XML-Quellcode

    1. <Style TargetType="{x:Type Path}">
    2. <Style.Triggers>
    3. <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Border}}, Path=IsMouseOver}" Value="True">
    4. <DataTrigger.EnterActions>
    5. <BeginStoryboard>
    6. <Storyboard>
    7. <ColorAnimation Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" From="White" To="Red" Duration="0"/>
    8. </Storyboard>
    9. </BeginStoryboard>
    10. </DataTrigger.EnterActions>
    11. <DataTrigger.ExitActions>
    12. <BeginStoryboard>
    13. <Storyboard>
    14. <ColorAnimation Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" From="Red" To="White" Duration="0"/>
    15. </Storyboard>
    16. </BeginStoryboard>
    17. </DataTrigger.ExitActions>
    18. </DataTrigger>
    19. </Style.Triggers>
    20. </Style>


    ____________________________________________________________________________
    Edit2:

    So jetzt muss ich doch nochmal nachhaken:

    Hab das mal in mein Projekt eingebaut, bekomme aber dann beim Starten des Programms diesen Fehler:

    InvalidOperationException: Diese Storyboard-Zeitleistenstruktur kann nicht für die threadübergreifende Verwendung fixiert werden.

    Also hab ich mal recherchiert und das hier gefunden:

    stackoverflow.com/questions/21…imation/14164245#14164245

    ...und dann probiert das umzubauen für meine Bedürfnisse, Betonung auf "probiert" :) :

    Spoiler anzeigen

    XML-Quellcode

    1. <Style TargetType="{x:Type Path}">
    2. <Setter Property="Stretch" Value="None"/>
    3. <Setter Property="Tag" Value="White"/>
    4. <Setter Property="Fill">
    5. <Setter.Value>
    6. <MultiBinding Converter="{StaticResource MultiplyConverter}">
    7. <Binding Path="Fill" RelativeSource="{RelativeSource Self}"/>
    8. <Binding Path="Tag" RelativeSource="{RelativeSource Self}"/>
    9. </MultiBinding>
    10. </Setter.Value>
    11. </Setter>
    12. <Style.Triggers>
    13. <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Border}}, Path=IsMouseOver}" Value="True">
    14. <DataTrigger.EnterActions>
    15. <BeginStoryboard>
    16. <Storyboard>
    17. <ColorAnimation Storyboard.TargetProperty="(Path.Tag).(SolidColorBrush.Color)" From="{DynamicResource Vordergrundfarbe}" To="Red" Duration="0"/>
    18. </Storyboard>
    19. </BeginStoryboard>
    20. </DataTrigger.EnterActions>
    21. <DataTrigger.ExitActions>
    22. <BeginStoryboard>
    23. <Storyboard>
    24. <ColorAnimation Storyboard.TargetProperty="(Path.Tag).(SolidColorBrush.Color)" From="Red" To="{DynamicResource Vordergrundfarbe}" Duration="0"/>
    25. </Storyboard>
    26. </BeginStoryboard>
    27. </DataTrigger.ExitActions>
    28. </DataTrigger>
    29. </Style.Triggers>
    30. </Style>


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class MultiplyConverter
    2. Implements IMultiValueConverter
    3. Public Function Convert(values() As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IMultiValueConverter.Convert
    4. Dim result As String = "White"
    5. For i = 0 To values.Length - 1
    6. If TypeOf values(i) Is String Then
    7. result = DirectCast(values(i), String)
    8. End If
    9. Next
    10. Return result
    11. End Function


    Aber bekomme immer noch den gleichen Fehler. Hat jemand vielleicht ne Idee was ich falsch mache? Oder kann mir zumindest den Code ein bisschen erklären, weil so 100%ig versteh ich das nicht....

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „kafffee“ ()

    Beim MultiValueConverter siehst du ja, kommen mehrere verschiedene objecte rein. Da kan alles drin stecken, string, int, etc. pp. Aber du gibst nur 1 Object raus, im Thread bei SO ein double. ConvertBack macht das anders herum, 1 object kommt rein, ein object[] geht raus. Achte auch auf TargetType, bei Convert hast du einen, bei ConvertBack einen Array, da gilt es dann einen passenden object-Array zu machen.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    Okay cool das hab ich verstanden. Was ich bloß nicht verstehe wie das das Problem mit dem Threading lösen soll. Ist das überhaupt die gleiche Fehlermeldung, auf die da auf stackoverflow drauf eingegangen wird, ich find es manchmal schwierig die Fehlermeldungen zu übersetzen, mir hat das halt Bing als Treffer ausgespuckt...

    Edit @DTF

    So hab wie gesagt noch einen anderen Ansatz gefunden, der das Problem behebt. Hab mir eine AttachedProperty gemacht:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.Windows
    3. Imports System.Windows.Controls
    4. Imports System.Windows.Media
    5. Imports System.Windows.Shapes
    6. Imports System.Windows.Input
    7. Namespace AttachedProperties
    8. Public Class ButtonAnimationHelper
    9. Inherits DependencyObject
    10. Public Shared Function GetButtonColor(obj As Path) As Brush
    11. Return DirectCast(obj.GetValue(ButtonColorProperty), Brush)
    12. End Function
    13. Public Shared Sub SetButtonColor(obj As Path, value As Brush)
    14. obj.SetValue(ButtonColorProperty, value)
    15. End Sub
    16. Public Shared ReadOnly ButtonColorProperty As DependencyProperty =
    17. DependencyProperty.RegisterAttached("ButtonColor",
    18. GetType(Brush),
    19. GetType(ButtonAnimationHelper),
    20. New PropertyMetadata(Brushes.Yellow, AddressOf ButtonColor_Changed))
    21. Private Shared Sub ButtonColor_Changed(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
    22. Dim ctl As Path = TryCast(d, Path)
    23. Dim parent As DependencyObject = VisualTreeHelper.GetParent(ctl)
    24. Dim parentBorder As Control
    25. If TypeOf parent Is Control Then
    26. parentBorder = CType(parent, Control)
    27. AddHandler parentBorder.MouseEnter, Sub(sender As Object, e2 As MouseEventArgs)
    28. DirectCast(ctl, Path).Fill = New SolidColorBrush(Colors.White)
    29. End Sub
    30. AddHandler parentBorder.MouseLeave, Sub(sender As Object, e2 As MouseEventArgs)
    31. DirectCast(ctl, Path).Fill = GetButtonColor(ctl)
    32. End Sub
    33. End If
    34. End Sub
    35. End Class
    36. End Namespace


    Aber so ganz rund läuft es noch nicht:

    Ich habe meine Paths nämlich manchmal als Child in einem Grid, manchmal ein Border, manchmal eine ViewBox usw... Von welchem Typ muss dann parentBorder sein, kann man das irgendwie verallgemeinern, oder muss ich für jeden Controltyp extra Code schreiben? Wenn ich direkt ein Path nehme, dann funtkioniert das bloss wenn der Mauszeiger direkt auf die "gezeichnete Fläche" trifft, nicht aber beim transparenten Teil des Paths...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Der Path hat keinen transparenten Teil, es sei denn du hast einen Path mit Fill = Transparent. Path = Pfad auf deutsch, in diesem Fall eine "Wegbeschreibung" um Figuren darzustellen.

    ICh denke du gehst auch falsch dran. Anstatt die Ursache für das Problem abzuschalten, suchst du einen Weg drumrum der alles nur verkompliziert. Auch in VS gibt es eine textsuchfunktion, da kannste auch einzeln durchsteppen und das aktuelle vorkommen mit was anderen austauschen. Mühselig, aber der richtige Weg.

    Ich denke du brauchst das Mouseenter und MouseLeave vom Parent, dort kannste eher attachen, an die Childs(die Path's) kommste dann ja ohne Probleme. Also bei den Grids und Bordern die in Frage kommen anhängen die Property. Aber das käme ja auch dem Aufwand vom entfernen der property aus dem XAML gleich oder nicht?
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    DTF schrieb:

    Der Path hat keinen transparenten Teil

    Ja, du weisst was ich mein. Eben nicht die Figur sondern alles Andere. Das Path-Element reagiert auf Mausklick nicht in einem rechteckigen Bereich sondern nur dort wo tatsächlich was gezeichnet wird....

    DTF schrieb:

    Ich denke du brauchst das Mouseenter und MouseLeave vom Parent

    Ja ganz genau das ist doch der Punkt. In meinem Code spreche ich ja in Zeile 31 und 34 das MouseEnter und MouseLeave vom Parent an. Funktioniert aber natürlich nur wenn parentBorder vom richtigen Typ ist. Ich dachte wenn ich Control nehme, spricht es vielleicht alle Arten von Parent an. weisst du wie ich meine?

    DTF schrieb:

    Aber das käme ja auch dem Aufwand vom entfernen der property aus dem XAML gleich oder nicht?

    Ganz genau. Bin grad sowieso am Überlegen ob das Ganze für mich überhaupt Sinn macht. Weil habs mal getestet, sooooo pricklend sieht es jetzt auch nicht aus, evtl. bleibe ich einfach bei einem animierten Rahmen um meine Paths...