I'm trying out styles in avalonia and most works, except for pseudoclasses, they just get ignored.
I have created a window and all styles are in there and I have created a user control (with a button on - the pseudoclasses are on the button), using the styles. I do not use code, only xaml to define the styles.
I have tried it out in the "Style Selector" for the button as "Button:pseudoclassname" and "Button.le:pseudoclassname". I have also tried "Button:pointerover" and "Button:hover" as the documentation mentions that that could be modified. No result. The styles for the pseudoclasses are all ignored, the others are all executed correct.
Is there something I'm doing wrong or is this a bug in avalonia ?
The xaml windows file:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:Hub.Views"
xmlns:vm="using:Hub.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Hub.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico"
Width="200" Height="300"
Title="Hub"
Classes="le">
<Window.Styles>
<Style Selector="Window.le">
<Setter Property="Background" Value="#191919"/>
</Style>
<Style Selector="Button.le">
<Setter Property="Background" Value="green"/>
<Setter Property="Foreground" Value="white"/>
</Style>
<Style Selector="Button.le:pointerover">
<Setter Property="Background" Value="red"/>
<Setter Property="Foreground" Value="white"/>
</Style>
<Style Selector="Button.le:pressed">
<Setter Property="Background" Value="blue"/>
<Setter Property="Foreground" Value="white"/>
</Style>
<Style Selector="TextBlock.le_update">
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="FontSize" Value="17"/>
<Setter Property="FontFamily" Value="Arial, Verdana"/>
<Setter Property="Foreground" Value="white"/>
<Setter Property="Background" Value="transparent"/>
</Style>
</Window.Styles>
<views:UpdateView/>
</Window>
The xaml user control file:
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Hub.Views.UpdateView">
<DockPanel>
<StackPanel DockPanel.Dock="Bottom">
<Button Classes="le" HorizontalAlignment="Center" HorizontalContentAlignment="Center" Width="300">
Check for updates
</Button>
</StackPanel>
<StackPanel Spacing="5" Margin="5">
<TextBlock Classes="le_update" HorizontalAlignment="Center" Margin="4">
No updates for Hub.
</TextBlock>
<TextBlock Classes="le_update" HorizontalAlignment="Center" Margin="4">
No updates for Engine.
</TextBlock>
</StackPanel>
</DockPanel>
</UserControl>
Button's Background property does get affected by your style, but at that point it has no effect on the actual Button's background, because Background property controls only the normal state of the button.
If you take a look at the default Button style here you can see that it passes its background to ContentPresenter via TemplateBinding:
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter x:Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
but overrides ContentPresenter's background in a style like this:
<Style Selector="Button:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />
Since it's ContentPresenter that actually draws the background (Button is a lookless control), you'll see the button to have ButtonBackgroundPointerOver and not the Button's Background property value.
So, you need to write a style that changes the inner ContentPresenter like this:
<Style Selector="Button.le:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="green" />
</Style>
Unfortunately that makes your styles theme-dependent since control templates are different between default and fluent themes.
The answer Kekekeks gave is the correct one for the question I asked.
However, I use this space in the hope to help novice users of avalonia with no background in xaml at all, like I do. Most of us look at avalonia to give our apps an interface that works on Windows/Mac/Linux. To be honest, at the moment of writing, no real alternatives in c# exist.
At this moment Avalonia does have examples and some documentation that is good, but not so for people not really having a background in xaml.
Therefore, go to Udemy or LikedIn.Learning or Youtube or wherever you find a good course on WPF AND AFTER THAT go to the documentation of Avalonia and start playing around.
The similarities that both (Avalonia and WPF) share is enormous !!! And yes it is mentioned a few times in the docs, but a blunt "Do go and learn WPF first if you are new to xaml !" on the frontpage of the documentation would have saved me a fair share of time in trying to find it all out via the website.
Fair is fair, the project still is in beta and the website is already well documented for that stage, so no blame to the team !
I have a series of button styles (add, edit, delete, etc.) that make use of the MahApps Metro cirucular button style but apply specific images to the button style. When I use any of the styles only once in a UserControl they work just fine and I get the anticipated look from the styles. However, when I use the styles more than once in a single UserControl, only one of the style instances acts as behaved, the others drop the image I am expecting to see.
I have tried naming the specific control instances (in case it was some sort of lifetime management issue) that are using the styles to see if this would fix the issue but it did not. I also tried creating multiple buttons that use the same style properties but do not use the style and that DID work and the buttons showed correctly, but I don't want to go that route as that would defeat the purpose of the styles.
Below is my code for the resource dictionary where I define the button styles. Please note that I have only shown the style for the add button as the other ones are basically the exact same I just change the image type and tool tip. That's why there is the circular button base that I use to define the majority of the style properties.
<!--Reference Dictionaries-->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" /> Source="pack://application:,,,/MahApps.Metro;component/Styles/FlatButton.xaml" />
</ResourceDictionary.MergedDictionaries>
<!--Circular Control Button Base-->
<Style x:Key="CircularControlButtonBase" TargetType="Button" BasedOn="{StaticResource MahApps.Metro.Styles.MetroCircleButtonStyle}">
<Setter Property="Height" Value="30"/>
<Setter Property="Width" Value="30"/>
<Setter Property="Margin" Value="2"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{DynamicResource GrayBrush1}"/>
<Setter Property="Foreground" Value="Black"/>
<Style.Triggers>
<!--IsMouseOver Trigger-->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource AccentColorBrush4}"/>
<Setter Property="Foreground" Value="{DynamicResource AccentColorBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource AccentColorBrush}"/>
<Setter Property="BorderThickness" Value="2"/>
</Trigger>
<!--IsEnabled Trigger-->
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource MahApps.Metro.Brushes.Badged.DisabledBackgroundBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
<!--Add Button-->
<Style TargetType="Button" x:Key="AddButton" BasedOn="{StaticResource CircularControlButtonBase}">
<Setter Property="ToolTip" Value="Add"/>
<!--Icon Image-->
<Setter Property="Content">
<Setter.Value>
<Rectangle Width="20" Height="20" Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill">
<VisualBrush.Visual>
<iconPacks:PackIconMaterial Kind="Plus"/>
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.OpacityMask>
</Rectangle>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And I consume the styles like this.
<UserControl x:Class ="TestClass"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--The image on this button won't come through.-->
<Button Style="{DynamicResource AddButton}"/>
<!--The image on this button will come through.-->
<Button Style="{DynamicResource AddButton}"/>
</UserControl>
I would expect that the the plus sign image would come through on both buttons, instead of just the last button in the xaml code. Any help would be appreciated.
The IconPacks control inside your style will be only created once. You can use the IconPacks control inside the ControlTemplate and bind to the content which is the enum value to avoid this issue:
<Style x:Key="AddButton"
BasedOn="{StaticResource CircularControlButtonBase}"
TargetType="Button">
<Setter Property="ToolTip" Value="Add"/>
<Setter Property="Content" Value="{x:Static iconPacks:PackIconMaterialKind.Plus}"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<iconPacks:PackIconMaterial Width="20" Height="20" Kind="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
<Button Style="{DynamicResource AddButton}"/>
<Button Style="{DynamicResource AddButton}"/>
<Button Style="{DynamicResource AddButton}"/>
</StackPanel>
Namespace are:
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
I'd like to have page headers in my app with either an icon or text centered in a 50px high bar at the top of the page. Optionally with a back-button.
For this reason I use a UserControl on each page which gets either one of those styles applied: PageHeaderStyle or PageHeaderBackStyle.
My implementation of one of those is the following (style definition in my App.xaml):
<Style x:Key="PageHeaderBaseStyle" TargetType="UserControl">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Height" Value="50" />
<Setter Property="Width" Value="NaN" />
<Setter Property="Background" Value="{StaticResource CDColor}" />
</Style>
<Style x:Key="PageHeaderStyle" TargetType="UserControl" BasedOn="{StaticResource PageHeaderBaseStyle}">
<Setter Property="Content">
<Setter.Value>
<Grid Background="{StaticResource CDColor}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" DataContext="{StaticResource MainPageModel}">
<TextBlock Style="{StaticResource PageHeaderTextBlockStyle}" Text="{Binding Title}" Visibility="{Binding TitleVisibility}" />
<Image Style="{StaticResource PageHeaderIconStyle}" Source="{Binding Icon}" Visibility="{Binding IconVisibility}" />
</Grid>
</Setter.Value>
</Setter>
</Style>
Applied like it should be:
<UserControl Style="{StaticResource PageHeaderStyle}" />
Now first I had used "Template" and applied a DataTemplate with the grid component. But this didn't work. Then I changed it to directly set the Content of the UserControl. This does work: After building the designer shows the page header (before it showed only the blue selection border, but no content - it was transparent).
But as soon as I start debugging the app on the emulator it disappears and the running app only shows a blank spot where it should be.
Why is this so? I mean after all the designer already shows it, why does it disappear then, though?
FYI: I do not get any binding exceptions nor any other. It just doesn't show up.
PS: I tried setting the Background in the base style while setting the grid's background to transparent. This didn't work either - only a blank spot.
Solved the problem: Best approach is probably to use a ContentControl. Using the Content property did not work, though. You have to use the ContentTemplate property. Using that one does work just fine.
In this post, I want to use a same solution to do with button. But I want to store the content to an other resource.(I mean XamlImage in below sample) What is the type for content of button to store xaml data in resource dictionary?
Below is sample from the post. I added XamlImage as path in resource but it doesn't work. So, what type should it be?
<Path x:Key="XamlImage" Data="M383.518,230.427C299.063,230.427 230.355,299.099 230.355,383.554 230.355,468.009 299.063,536.644 383.518,536.644 467.937,536.644 536.645,468.009 536.645,383.554 536.645,299.099 467.937,230.427 383.518,230.427z M340.229,0L426.771,0C436.838,0,445.035,8.19732,445.035,18.2643L445.035,115.303C475.165,122.17,503.532,133.928,529.634,150.43L598.306,81.6869C601.721,78.3074 606.359,76.3653 611.213,76.3653 616.031,76.3653 620.704,78.3074 624.12,81.6869L685.278,142.916C692.397,150.035,692.397,161.648,685.278,168.767L616.677,237.402C633.108,263.54,644.866,291.907,651.733,322.001L748.736,322.001C758.803,322.001,767,330.198,767,340.265L767,426.806C767,436.873,758.803,445.07,748.736,445.07L651.769,445.07C644.901,475.235,633.108,503.531,616.677,529.669L685.278,598.305C688.694,601.72 690.635,606.358 690.635,611.212 690.635,616.102 688.694,620.705 685.278,624.12L624.085,685.313C620.525,688.872 615.851,690.67 611.177,690.67 606.503,690.67 601.865,688.872 598.269,685.313L529.67,616.678C503.567,633.109,475.2,644.937,445.035,651.804L445.035,748.771C445.035,758.838,436.838,767,426.771,767L340.229,767C330.162,767,321.965,758.838,321.965,748.771L321.965,651.804C291.8,644.937,263.433,633.109,237.366,616.678L168.731,685.313C165.315,688.693 160.677,690.67 155.823,690.67 151.005,690.67 146.296,688.693 142.916,685.313L81.7221,624.12C74.6033,617.036,74.6033,605.424,81.7221,598.305L150.323,529.669C133.892,503.603,122.099,475.235,115.267,445.07L18.2643,445.07C8.19734,445.07,0,436.873,0,426.806L0,340.265C0,330.198,8.19734,322.001,18.2643,322.001L115.267,322.001C122.135,291.907,133.892,263.54,150.323,237.402L81.7221,168.767C78.3064,165.351 76.3655,160.713 76.3655,155.859 76.3655,150.97 78.3064,146.332 81.7221,142.916L142.916,81.7582C146.476,78.1988 151.149,76.4016 155.823,76.4016 160.497,76.4016 165.171,78.1988 168.731,81.7582L237.366,150.43C263.469,133.928,291.837,122.17,321.965,115.303L321.965,18.2643C321.965,8.19732,330.162,0,340.229,0z"/>
<Style x:Key="PathAppBarButtonStyle" BasedOn="{StaticResource AppBarButtonStyle}" TargetType="ButtonBase">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Path Width="20" Height="20"
Stretch="Uniform"
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Data="{Binding Path=Content, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</DataTemplate>
</Setter.Value>
</Setter>
<Style x:Key="CrossButtonStyle" TargetType="ButtonBase" BasedOn="{StaticResource PathAppBarButtonStyle}">
<Setter Property="AutomationProperties.AutomationId" Value="CrossAppBarButton"/>
<Setter Property="AutomationProperties.Name" Value="Cross"/>
<Setter Property="Content" Value="{StaticResource XamlImage}"/>
</Style>
You don't want to set an image resource as your content because Image is a control and it can only be in one place in your UI tree. You can reuse a DataTemplate though in your ContentTemplate. So just put an Image inside of that.
I am writing a Store app with XAML and C#. I want to use Border and ViewBox. I got border styled, so I do not have to set properties that many times. I set BorderThickness to 2, and color to White, but this causes problems in my Viewbox.
Here it is in XAML:
<Viewbox Grid.Row="1" Stretch="Uniform">
<Grid Width="600" Height="600">
<Grid.Resources>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="White" />
<Setter Property="BorderThickness" Value="2" />
</Style>
<Style TargetType="Grid">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Width" Value="150" />
<Setter Property="Height" Value="150" />
</Style>
</Grid.Resources>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<Grid>
<Border>
<Viewbox>
<TextBlock Text="T" />
</Viewbox>
</Border>
</Grid>
The result of this is:
The problem is the scaled border around the letter "T".
I do not want to remove above styling for Border in Grid.Resources. I found only one solution so far...
<Viewbox>
<Viewbox.Resources>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="White" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</Viewbox.Resources>
<TextBlock Text="T" />
... what would give correct result:
, but I do not want to put these lines after each ViewBoxes, because there will be many.
I also tried to make a component, what has this default "resource" of zero thick border, but that had bad scaling.
So my question is how to to remove that border?
You're right to use the zero value for BorderThickness. There just might be another element in the visual tree hierarchy that also holds a default value that causes this.
I can't test this right now, but I can recommend this tool to you:
http://blois.us/Snoop/
You can inspect the visual tree with this by dragging the crosshair above your running debug application. Every time I stumbled upon a problem like this I found it highly useful to see which controls really appear at runtime, because with xaml it can be really tough to know it all. Hope you can find it!