Wpf: A more compact Style format

Created on 30 Mar 2019  路  8Comments  路  Source: dotnet/wpf

Allow us to write Styles like this:

<Style Key="Style1" TargetType="Control">
   <Set
    Foreground = "#66603a"
    Background = "#fff4e4"
    BorderBrush = "Red"
    BorderThickness = ".5,.5,1.5,1.5"          
    FontFamily = "Times New Roman" 
    FontSize= "18" 
    FontWeight = "Bold" 
    FontStyle = "Oblique"
    Padding = "5" 
    Margin = "10" />

    <Handle MouseEnter ="Control_MouseEnter"/>
</Style>

this is more compact and more readable than:

<Style Key="Style1" TargetType="Control">
      <Setter Property="Control.Foreground" Value="#66603a" />
      <Setter Property="Control.Background" Value="#fff4e4"/>
      <Setter Property="Control.BorderBrush" Value="Red"/>
      <Setter Property="Control.BorderThickness" Value=".5,.5,1.5,1.5"/>          
      <Setter Property="Control.FontFamily" Value="Times New Roman" />
      <Setter Property="Control.FontSize" Value="18" />
      <Setter Property="Control.FontWeight" Value="Bold" />
      <Setter Property="Control.FontStyle" Value="Oblique"/>
      <Setter Property="Control.Padding" Value="5" />
      <Setter Property="Control.Margin" Value="10" />

    <EventSetter Event="MouseEnter"  Handler="Control_MouseEnter"/>
</Style>
issue-type-api-suggestion

Most helpful comment

Hi @VBAndCs,

ok, I understand. The idea is to extend the XAML Parser, so that it understands the Set tag as a shorthand syntax for the setters.

All 8 comments

For complex value, there is a little to enhance:

<Style>
        <Set BorderBrush="new()">
                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <GradientStop Color="Yellow" Offset="0.0" />
                    <GradientStop Color="Red" Offset="0.25" />
                    <GradientStop Color="Blue" Offset="0.75" />
                    <GradientStop Color="LimeGreen" Offset="1.0" />
                </LinearGradientBrush>
        </Set>
</Style>

instead of

<Style>
        <Setter Property="BorderBrush" >
            <Setter.Value>
                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <GradientStop Color="Yellow" Offset="0.0" />
                    <GradientStop Color="Red" Offset="0.25" />
                    <GradientStop Color="Blue" Offset="0.75" />
                    <GradientStop Color="LimeGreen" Offset="1.0" />
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
</Style>

Hi @VBandCS,

great suggestion. You introduced a Set type with this snippet:

<Style Key="Style1" TargetType="Control">
   <Set
    Foreground = "#66603a"
    Background = "#fff4e4"
    BorderBrush = "Red"
    BorderThickness = ".5,.5,1.5,1.5"          
    FontFamily = "Times New Roman" 
    FontSize= "18" 
    FontWeight = "Bold" 
    FontStyle = "Oblique"
    Padding = "5" 
    Margin = "10" />

    <Handle MouseEnter ="Control_MouseEnter"/>
</Style>

But what if you want to create a style for another FrameworkElement, or a Control subclass? Then you need to find the properties of that other FrameworkElement or Control subclass on the Set type. That would mean there needs to be a Set type for every control type or the properties need to be dynamic somehow. This makes it complicated an I think this was a reason that led to the solution that we have today with Setters that can set any Dependency Property (That doesn't mean that there's not a better way to do it. :))

The second snippet in your first post doesn't need the Control class for the Property attributes, as you've specified it already in the TargetType. You can write it a bit shorter like this:

<Style Key="Style1" TargetType="Control">
      <Setter Property="Foreground" Value="#66603a" />
      <Setter Property="Background" Value="#fff4e4"/>
      <Setter Property="BorderBrush" Value="Red"/>
      <Setter Property="BorderThickness" Value=".5,.5,1.5,1.5"/>          
      <Setter Property="FontFamily" Value="Times New Roman" />
      <Setter Property="FontSize" Value="18" />
      <Setter Property="FontWeight" Value="Bold" />
      <Setter Property="FontStyle" Value="Oblique"/>
      <Setter Property="Padding" Value="5" />
      <Setter Property="Margin" Value="10" />

    <EventSetter Event="MouseEnter"  Handler="Control_MouseEnter"/>
</Style>

Then the next one with the single setter for complex types. Instead of

<Style>
        <Setter Property="BorderBrush" >
            <Setter.Value>
                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <GradientStop Color="Yellow" Offset="0.0" />
                    <GradientStop Color="Red" Offset="0.25" />
                    <GradientStop Color="Blue" Offset="0.75" />
                    <GradientStop Color="LimeGreen" Offset="1.0" />
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
</Style>

you can write

<Style>
        <Setter Property="BorderBrush" >
            <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <GradientStop Color="Yellow" Offset="0.0" />
                    <GradientStop Color="Red" Offset="0.25" />
                    <GradientStop Color="Blue" Offset="0.75" />
                    <GradientStop Color="LimeGreen" Offset="1.0" />
                </LinearGradientBrush>
        </Setter>
</Style>

when Issue https://github.com/dotnet/wpf/issues/84 is fixed. The fix will be a one-liner, adding the ContentPropertyAttribute to the Setter class.

Hi @thomasclaudiushuber
There is no need to create a Set type. Parse <Set /> as an xml tag and get its Attr / Value pairs, then create a XAML Setter for each pair, and them to the Style. This can happen in run-time or in the precompiled BAML. This is a straight forward easy solution.
The only work to do, is make the editor / Xaml parser check that each attr written in the Set tag is a property in the TargetType with a valid value, of course with intellisense support.
This should be easier in the absence of the TargetType , where each attr (property) is fully qualified (i.e Control.Foreground = ...).
My aim here is to have a 2-stage Xaml parsing, to allow using some shortcut syntax, that expanded in run-time to the formal Xaml syntax.

Hi @VBAndCs,

ok, I understand. The idea is to extend the XAML Parser, so that it understands the Set tag as a shorthand syntax for the setters.

@thomasclaudiushuber
Exactly. I posted another proposal but in the XAML Slandered repo. In fact I don't know which repo is responsable for Xaml:
https://github.com/Microsoft/xaml-standard/issues/236

I had these ideas while I am working on Vazor. I use the VB XML literal to generate the Razor. I thought about using such technique with XAML somehow, or use xaml styles instead of CSS in Razor, but I found xamle style too verbose, so I thought of this. I add a middle stage between xml and razor, so, I though that this will be helpful in Xaml, especially it is dynamic and can be generated in run-time. I think we need to revise Xaml syntax and make it as shorter as possible.

HI @VBAndCs

I think posting this suggestion into this repo is good, as this is the official WPF repo.
For UWP XAML this repo is the way to go: https://github.com/Microsoft/microsoft-ui-xaml

Thanks,
Thomas

Thank you @VBAndCs and @thomasclaudiushuber for the awesome discussion here! I think both https://github.com/Microsoft/microsoft-ui-xaml and here are a good place to open issues like this, quite a few of us work on both technologies so it will be seen. I personally think any improvements like this should be synchronized across UWP, WPF, and Xamarin.Forms.

It's unfortunate what has happened to https://github.com/Microsoft/xaml-standard repo, although i'm hopeful that we can still align XAML dialects without necessarily creating a "XAML standard".

It seems nobody has mentioned Xamarin.Forms CSS support.

Like WPF, Xamarin.Forms has support for XAML-based styles using resource dictionaries (see e.g. here), but it adds an alternate syntax in the form of (modified) CSS.

This is interesting because:

  • although this is a slightly different dialect (for example, there's a notion of "match this type as well as ones that inherit from it"), web developers will quickly be familiar
  • while XML is a good fit for the controls tree, I'm not sure it was ever a good idea to represent styles in it

I would love to see some collaboration so that an evolved form of Xamarin.Forms's CSS can be used in WPF as well.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

daniel-white picture daniel-white  路  3Comments

pocki picture pocki  路  3Comments

Pzixel picture Pzixel  路  3Comments

JeroenOortwijn picture JeroenOortwijn  路  3Comments

h82258652 picture h82258652  路  3Comments