API Design - Why BorderBrush has no effect on CheckBox? - wpf

In UWP, the BorderBrush has no effect on the CheckBox. The BorderThickness does have an effect, you can see there's like a transparent border around the control:
<CheckBox BorderBrush="Red"
BorderThickness="10"
Background="Aqua"
Content="CheckBox" />
<RadioButton BorderBrush="Red"
BorderThickness="10"
Background="Aqua"
Content="RadioButton" />
The RadioButton works differently, it does use the brush.
I'm NOT looking to understand how to make the CheckBox use the border brush, I already know that.
What I'm looking for is to understand WHY did the UWP team decide to make it work like that? Is it just a bug or a slip from their side? I find it hard to believe it.
What's interesting is that in WPF, the border works differently for both the CheckBox and RadioButton:
I'm also curious to know why the WPF team made the decision to have the BorderThickness and BorderBrush work differently on CheckBox and RadioButton than for other controls which show border around the whole control. Button is the closest example. Is it maybe because they didn't want to add more specialized properties to customize the actual check/radio? If that's the case, didn't they lose the option to have a border around the whole control?

Hex Code for color makes the trick
<CheckBox BorderBrush=" #000000" Grid.Column="3" Grid.Row="0" BorderThickness="10" Background="Aqua" Content="CheckBox" />
Else you could use color converter and call it on the control

For explaining this behaviour, you need to check CheckBox styles and templates. As you see CheckBox has some status in the VisualStateGroups. you just modify BorderBrush property but you have not modify the following StaticResource that used for different VisualState.
<StaticResource x:Key="CheckBoxBorderBrushUnchecked" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CheckBoxBorderBrushUncheckedPointerOver" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CheckBoxBorderBrushUncheckedPressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CheckBoxBorderBrushUncheckedDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CheckBoxBorderBrushChecked" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CheckBoxBorderBrushCheckedPointerOver" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CheckBoxBorderBrushCheckedPressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CheckBoxBorderBrushCheckedDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CheckBoxBorderBrushIndeterminate" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CheckBoxBorderBrushIndeterminatePointerOver" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CheckBoxBorderBrushIndeterminatePressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CheckBoxBorderBrushIndeterminateDisabled" ResourceKey="SystemControlTransparentBrush" />
If you want modify border color completely, you need to modify the above StaticResource, for example.
Method 1
Make a new SolidColorBrush with CheckBoxBorderBrushxxxxx key to cover the default one.
<SolidColorBrush x:Key="CheckBoxBorderBrushUnchecked" Color="Red"/>
Method 2
Use the the default StaticResource, but modify ResourceKey to another one.
<StaticResource x:Key="CheckBoxBorderBrushUnchecked" ResourceKey="SystemChromeBlackLowColor" />
Update
This is latest CheckBox full xaml template

Related

Why does my Ribbon Menu Button Popup disappear when I apply this Style?

Here is my XAML:
<Ribbon x:Name="ribbonMain" Height="200" ContextMenu="{x:Null}" VerticalAlignment="Top" ShowQuickAccessToolBarOnTop="False" >
<RibbonTab x:Name="ribbonTabMain" Header="Test Tab" ContextMenu="{x:Null}" >
<RibbonGroup x:Name="ribbonGroupMain" Header="Test Group" ContextMenu="{x:Null}">
<RibbonButton x:Name="ribbonButtonMain" Label="Test Button" ContextMenu="{x:Null}" />
</RibbonGroup>
<RibbonGroup x:Name="ribbonGroupMain2" Header="Test Group 2" ContextMenu="{x:Null}">
<RibbonMenuButton ContextMenu="{x:Null}" Name="ribbonMenuButtonMain" Label="Menu Button">
<RibbonMenuItem ContextMenu="{x:Null}" Name="ribbonMenuItemMain" Header="Menu Item"></RibbonMenuItem>
<RibbonMenuItem ContextMenu="{x:Null}" Name="ribbonMenuItemMain2" Header="Menu Item 2"></RibbonMenuItem>
</RibbonMenuButton>
</RibbonGroup>
</RibbonTab>
</Ribbon>
I then run this C# Code to get the Ribbon Menu Button Default Control Template:
string ribbonMenuButtonControlTemplate = XamlWriter.Save(ribbonMenuButtonMain.Template);
After that I set the x:Name and x:Key properties of the Control Template to something and then put that string of XAML in this:
<Style TargetType="RibbonMenuButton"
<Setter Property="Template">
<Setter.Value>
{DefaultControlTemplateHere}
</Setter.Value>
</Setter>
</Style>
Last I put that Style in my <Window.Resources>.
I wanted to alter the Style from there, but then I realized that the popup just wasn't working anymore.
I expected nothing to change. Seems I was mistaken.
Why does this happen?
Note:
I've tried running this code to see if the popup would open:
if (!ribbonMenuButtonMain.IsDropDownOpen)
{
ribbonMenuButtonMain.IsDropDownOpen = true;
}
With no Style applied that code runs fine and the popup opens.
But with the Style I get this exception:
System.InvalidOperationException: 'This Visual is not connected to a
PresentationSource.'
The XamlWriter.Save method has some serialization limitations that are mentioned here. One of them being that;
Common references to objects made by various markup extension formats, such as StaticResource or Binding, will be dereferenced by the serialization process. These were already dereferenced at the time that in-memory objects were created by the application runtime, and the Save logic does not revisit the original XAML to restore such references to the serialized output.
So your generated template is missing a TemplateBinding to the IsOpen property of the Popup:
<Popup ... IsOpen="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsDropDownOpen}">
You may extract the default template including any bindings from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\System.Windows.Controls.Ribbon.dll using a decompiler such as for example dotPeek.

WPF Visibility Resource with Binding

I got a WPF Application using MVVM Light. In one View i got many Controls which are using the same visibility binding. Because i dont like to insert my long binding path to every control. I'd like to use a Resource...
<SomeControl>
<SomeControl.Resource>
<Visibility x:Key="myVisibilityResource" >
<Binding Path="somePath" Converter="BoolToVisibilityConverter"></Binding>
</Visibility>
</SomeControl.Resource>
<SomeControl>
With this version i get the Error that Visibility does not support direct content. I would have to write it like this:
<Visibility x:Key="myVisibilityResource" >
Collapsed
</Visibility>
Any ideas?
If all you want is to be able to write "Visible" or "Collapsed" in your XAML (as in your last example) you can do it by binding to and ObjectDataProvider which is uses Enum.Parse to parse the given text (which can be "Visible", "Collapsed", or "Hidden"):
<Grid xmlns:sys="clr-namespace:System;assembly=mscorlib" >
<Grid.Resources>
<ObjectDataProvider x:Key="visibilityProvider"
MethodName="Parse"
ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="Visibility" />
<sys:String>Visible</sys:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Grid.Resources>
<Button x:Name="button1" Visibility="{Binding Source={StaticResource visibilityProvider}}" />
</Grid>
In the above code I am using an ObjectDataProvider to return a Visibility enumeration. The ObjectDataProvider calls Enum.Parse when binding. The button's Visibility property binds to the ObjectDataProvider.
The MethodParameters property specifies the parameters for Enum.Parse.
Unfortunately there is no way to bind MethodParameters directly to an underlying ViewModel. If you want to do this, I guess you could write your own ObjectDataProvider or you could use your own class/method instead of Enum.Parse which returns the correct Visibility value.
Create a style in resources:
<Style TargetType="Control" x:Key="VisibilityStyle">
<Setter Property="Visibility"
Value="{Binding Converter={StaticResource VisibleIfFalse}}"/>
</Style>
Then simply add the reference to the item to hide/show.
<TextBlock Text="123" Style="{StaticResource VisibilityStyle}"/>
<TextBlock Text="123" Style="{StaticResource VisibilityStyle}"/>
<TextBlock Text="123" Style="{StaticResource VisibilityStyle}"/>
<TextBlock Text="123" Style="{StaticResource VisibilityStyle}"/>
This also works for headers of grids...
How about something like this? It's not exactly what you asked for, but you would be copying less code around since you wouldn't have to include the converter every time.
<UserControl>
<Grid>
<SomeElement x:Name="Master" Visibility="{Binding somePath, Converter={StaticResource BoolToVisibilityConverter}}" />
<SomeOtherElement Visibility="{Binding Visibility, ElementName=Master}" />
<SomeOtherElement Visibility="{Binding Visibility, ElementName=Master}" />
</Grid>
</UserControl>

Center checkbox in UniformGrid's cells in WPF

I want to center and stretch checkbox in UniformGrid's cell.
I've tried to do it in many ways:
<UniformGrid>
<CheckBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center" />
<CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" />
<CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" ClipToBounds="True" />
<CheckBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ClipToBounds="True" />
Selected cell (0, 0):
Selected cell (1, 0):
but it doesn't satisfy me because I want to stretch (just like in cell (0,0)) and center (just like in (1,0)) those checkboxes in their cells simultaneously.
How can I do it?
[edit 1]
I'm trying to make it so that I don't have to click the little check but instead can click the entire cell.
[edit 2]
Actually I want to add those checkboxes from C# code so if solution made in XAML is not 'portable' to C# language it will be not very helpful.
If I use this simple markup with the default Stretch values:
<UniformGrid>
<CheckBox Content="This is a checkbox" />
<CheckBox Content="This is a checkbox" />
<CheckBox Content="This is a checkbox" />
<CheckBox Content="This is a checkbox" />
</UniformGrid>
I am able to click anywhere in each cell of the UniformGrid to check and uncheck the Checkbox in that cell.
Functionally this is doing what you want. if you want to change the appearance of the checkbox, you can use a ControlTemplate.
If you don't want to change the size of the CheckBox and you just want to center it visually while being able to click the cell to check it, you could use a template like this:
<CheckBox>
<CheckBox.Template>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid Background="Transparent">
<CheckBox IsChecked="{TemplateBinding Property=IsChecked}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</CheckBox.Template>
</CheckBox>
EDIT:
To apply it as a resource at runtime, write the XAML in a resource section of the appropriate scope. You can place it in the local Resources dictionary if you only need it in one control, or if you want access to it globally, put it in the App.xaml like so:
<Application.Resources>
<ControlTemplate x:Key="StretchedCheckBox" TargetType="{x:Type CheckBox}">
<Grid Background="Transparent">
<CheckBox IsChecked="{TemplateBinding Property=IsChecked}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Application.Resources>
Notice how it has a key "StretchedCheckBox". Now you can use that to apply it in code:
ControlTemplate stretchedTemplate = FindResource("StretchedCheckBox") as ControlTemplate;
CheckBox chkBox = new CheckBox();
chkBox.Template = stretchedTemplate;
I don't think you can affect the size of a CheckBox like that because the size is pre-determined in the control template
One solution would be to use a LayoutTransform to scale the CheckBox to be larger
<CheckBox>
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="5" ScaleY="5" />
</CheckBox.LayoutTransform>
</CheckBox>
It should be noted that this scales the text next to the CheckBox as well as the CheckBox itself, and sometimes doesn't look very nice depending on how you scale it.
Another alternative solution is to copy the example CheckBox template from MSDN, and create a larger CheckBox

How to determine if a custom control is in a Toolbar?

i have created a UserControl to make an ImageButton:
<Button x:Class="myimagebutton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:imagebutton">
<Grid x:Name="grdButton">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
x:Name="btnImage"
HorizontalAlignment="Left"
VerticalAlignment="Center">
</Image>
<TextBlock Grid.Column="1"
TextWrapping="Wrap"
Text="{Binding Text}"
VerticalAlignment="Center"
Margin="2 0 2 0" />
</Grid>
</Button>
now i want to apply the default Toolbar Button Style to my Button if this Button is in a Toolbar. I have read this article link text and put this
If Me.Style Is Nothing AndAlso TypeOf Me.Parent Is ToolBar Then
Me.Style = DirectCast(FindResource(ToolBar.ButtonStyleKey), Style)
End If
in my Code behind.
After that as a test I put my Button both in a Toolbar and another out of the Toolbar to test it. But the Button always get the default style, not the style I am trying to set.
After debugging i find out that Me.Parent is always Nothing. So now is my question: how i get the information that my button is in a toolbar or not?
I'm having some difficulty understanding exactly what you are describing but after reading it through a few times I think I understand.
Am I right so far?
If so, you are wondering then why your button has an image
A few pointers about your description that threw me off and is probably the reason why you haven't seen anybody else post an answer for your question thus far.
i replaced the the UserControl Item with a Button
Essentially what you have done is created new control that likely inherits from Button. You might have started off with a UserControl but in order to replace the root item in XAML you would also have to make sure your type myimagebutton inherits from Button as well. This is just how XAML works and learning how to explain it this way will help people understand what you are doing.
Normally inheriting from Button is not how developers override the visual style of a button in WPF mainly because WPF doesn't support the concept of what is sometimes referred to as visual inheritance and also there are other suitable methods that can be used to solve the problem in a different way. Instead inheritance is mainly reserved for when behavioral modifications or additions need to be made to an existing control class. This being said there are ways to simulate visual inheritance through the use of content controls that work similar to content pages and master pages in ASP.NET but I think this is a bit outside of the scope of your example. Also if you are to pursue the inheritance model you will need to make sure that in your code behind that you are setting the correct default style in the static constructor so posting your code behind for your button would help too.
I believe the reason why your example isn't working is because the ToolBar specifically looks at the types of controls irrespective inheritance in order to to apply it's custom toolbar styles. In your case your control is of type myimagebutton and not Button so the style is not set by the ToolBar which normally directly sets the Style property based on the type of the control using the two potential types of calls.
element.SetResourceReference(FrameworkElement.StyleProperty, styleKey);
element.DefaultStyleKey = styleKey;
BTW, in your case I believe only the second line is performed by the ToolBar control and styleKey at that point is defined as null.
Now instead of inheriting from Button in the first place you would probably be better off just to create a new ControlTemplate or a DataTemplate for your button and assigning into the Template or ContentTemplate property respectively through the use of a style. This way you are still always dealing with a button and the style is what changes the visual properties.
<Window x:Class="HeaderedContentControlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="252"
Width="372">
<Window.Resources>
<Style TargetType="{x:Type Label}">
<Setter Property="Background"
Value="Orange" />
</Style>
<DataTemplate x:Key="ImageButtonDataTemplate">
<Grid x:Name="grdButton">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
HorizontalAlignment="Left"
VerticalAlignment="Center">
</Image>
<TextBlock Grid.Column="1"
TextWrapping="Wrap"
Text="{Binding}"
VerticalAlignment="Center"
Margin="2 0 2 0"
Background="Pink" />
</Grid>
</DataTemplate>
<Style x:Key="ImageButtonStyle"
TargetType="{x:Type Button}">
<Setter Property="ContentTemplate"
Value="{StaticResource ImageButtonDataTemplate}" />
</Style>
</Window.Resources>
<Grid Margin="11">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ToolBar>
<Button Style="{StaticResource ImageButtonStyle}"
Content="Some Text" />
</ToolBar>
<Button Grid.Row="1"
Style="{StaticResource ImageButtonStyle}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Content="Some Text" />
</Grid>
</Window>
Using the ContentTemplate allows you to redefine the inner contents of the Button without loosing all of the special button state transitions and other niceties you would normally like to keep.
See this related post on MSDN Forums that also explains similar behavior when adding a StackPanel containing buttons to a ToolBar.

WPF - Add Custom Font

I'm trying to add a custom font as a resource in my application.
I have a "CustomFont" directory in the application and all the fonts inside of it are set to "Resource"
<Window.Resources>
<Style x:Key="Gotham-XLight">
<Setter Property="TextElement.FontFamily"
Value="/CustomFonts;Component/#Gotham-XLight" />
</Style>
</Window.Resources>
And then on my TextBlock I have this: (inside a grid)
<TextBlock x:Name="TimeTextBlock" Style="{DynamicResource Gotham-XLight}"
TextAlignment="Center" FontSize="25" FontWeight="Bold"
Foreground="White" Text="TextBlockTimer"
Margin="105,242.974,0,226.975" HorizontalAlignment="Left"
Width="221.919" />
But I'm not seeing my font as people say. Am I doing something wrong?
You may want to check the name of the font, you need to specify the name of the font not the name of the file.
Double click on the font file and it should show a "Font name:" that's what you want to make sure is specified in your style.
Try this
<Window.Resources>
<Style x:Key="Gotham-XLight">
<Setter Property="TextElement.FontFamily" Value="CustomFonts/#Gotham-XLight" />
</Style>
</Window.Resources>
Also, if you are not planning on changing the style at runtime {StaticResource Gotham-XLight} will be much more performant.
In xaml I did it like this:
<Button Grid.Column="1" Grid.RowSpan="2" Name="start" Margin="5" Click="start_Click">
<TextBlock Name="test" FontFamily="pack://application:,,,/Y_Yoga;Component/Resources/#FontAwesome"></TextBlock>
</Button>
However, I don't know if #FontAwesome is font's embedded name or is it the result that I renamed the .ttf file.
Hope to be helpful!
Late reply but worth mentioning. To add a custom font that will apply globally in your window you could add this in your csproj file to include the fonts from the Fonts folder of your project as resources.
<ItemGroup>
<Resource Include="Fonts\*.ttf" />
</ItemGroup>
Then in your window XAML you can specify the FontFamily in the Window part:
<Window x:Class="Namespace.MainWindow"
...
FontFamily="/Fonts/#[FONT NAME]"
Title="">
<Grid>
...
</Grid>
</Window>
I hope this could help somebody, as I spent some time to figure it out.

Resources