WPF CheckBox is not squared - wpf

I have a strange bug here. CheckBox controls has always been squared. Now I've noticed that it's not. It's one pixel wider than tall. After experimenting a bit with empty WPF applications, I've discovered that it depends on the UseLayoutRounding setting. If it's set to false, the CheckBox is never a square. If it's set to true, it depends on the actual layout values and how they are rounded, or snapped to pixels.
Just create an empty WPF application targeting .NET Framework 4.5.2, 4.6 or 4.6.1 (I've tested these) and run it on Windows 10. Here's the minimal XAML to reproduce. The third state shows another filled "square" box that makes it easier to recognise the form without measuring pixels.
<Window
x:Class="CheckBoxTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" UseLayoutRounding="False">
<Grid>
<CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" IsThreeState="True" IsChecked="{x:Null}"/>
</Grid>
</Window>
Then drag the window's width and watch the CheckBox as it toggles between square and one pixel wider. In another of my applications it's always one pixel wider and never has a squared form.
Is that a bug in WPF? Does it only happen on Windows 10?
PS: Better not use a high DPI monitor for this, it may be harder to see there.

Its a bug in the default style of the checkbox. For some reason they decided to not use layout rounding on the grid in the checkbox control template.
<Border x:Name="checkBoxBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid x:Name="markGrid" UseLayoutRounding="True">
<Path x:Name="optionMark" Data="F1 M 9.97498,1.22334L 4.6983,9.09834L 4.52164,9.09834L 0,5.19331L 1.27664,3.52165L 4.255,6.08833L 8.33331,1.52588e-005L 9.97498,1.22334 Z " Fill="{StaticResource OptionMark.Static.Glyph}" Margin="1" Opacity="0" Stretch="None"/>
<Rectangle x:Name="indeterminateMark" Fill="{StaticResource OptionMark.Static.Glyph}" Margin="2" Opacity="0"/>
</Grid>
</Border>
Maybe because even if you modify the template like this, it still inchworms when you resize it in the designer, but not when you run it.

Related

ContentPresenter loosing it data binding after triggers invoked more than twice

I have created an extended button with 2 different border styles invoked by triggers in XAML. Both share the same contentpesenter but after changing the border style more than twice the content in the contentpresenter fails to display.
Below is a link to the entire project with a test bed application that demonstrates the issue, I think the issue is somewhere in the XAML below but I cannot see why it breaks:
Sample Button App
<Style.Resources>
<ContentPresenter x:Key="ButtonContent" Margin="5" HorizontalAlignment="Center"
Content="{Binding Content}"/>
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Margin="{Binding KeyMargin}">
<Grid Visibility="{Binding RectangleVisibility}">
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=rectBorder}" />
</Grid.OpacityMask>
<Border x:Name="rectBorder"
CornerRadius="{Binding BorderCorners}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="{Binding BorderThickness}"/>
<Viewbox Stretch="Fill"
StretchDirection="Both">
<ContentControl Content="{StaticResource ButtonContent}"/>
</Viewbox>
</Grid>
<Grid Visibility="{Binding EllipseVisibility}">
<Ellipse Stroke="{TemplateBinding BorderBrush}"
StrokeThickness="{Binding BorderThickness}"
Fill="{TemplateBinding Background}">
</Ellipse>
<Viewbox Stretch="Fill"
StretchDirection="Both">
<ContentControl Content="{StaticResource ButtonContent}"/>
</Viewbox>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
The problem is most likely that you cannot have the same element (the ContentPresenter in this case) in more than one place in the visual tree, and in which one of the two grids it ends up is undefined, i.e., an implementation archetype of WPF.
To get the element duplicated this might work:
<ContentControl Content="{TemplateBinding Content}"/>
or in your case
<ContentControl Content="{TemplateBinding Content}" Margin="5" HorizontalAlignment="Center"/>
instead of a static resource. The <ContentPresenter/> syntax is pretty much an optimized shortcut for that (or you could set x:Shared="False" on the resource, but having a ContentPresenter as a static resource is as far as I know not how it is intended to be used)
If the Button content is a UIElement itself though, it will be used directly itself in the visual tree, i.e., twice and this wont work either. A better solution would be to just have the content once in the control template and change the visual appearance around it, e.g., using a trigger to set the Grid's OpacityMask.
Another remark is that your control template is very tightly bound to where the Button is used, with direct bindings to the current data context, which reduces its reusability. Some easy fixes is to use TemplateBinding instead of Binding for BorderThickness respectively Margin (instead of KeyMargin), since those are existing properties of the Button.
For better reusability and cleaner code you should consider looking into creating a custom control deriving from Button with dependency properties for BorderCorners, the desired visual state (ellipse vs rectangle) etc. You might also want to use triggers to get the mouse-over effects of the button etc. Have fun control templating!

Is there a way to see DropShadowEffect on designtime?

I want to attach a DropShadowEffect on a Border control. I see it on runtime but not in the designer.
<Grid>
<Border Background="LightGray"
BorderBrush="DarkGray"
BorderThickness="1"
ClipToBounds="True"
Width="400"
Height="100">
<Border Background="Transparent"
BorderBrush="Black"
BorderThickness="0,10,0,0"
Margin="0,-11,0,0">
<Border.Effect>
<DropShadowEffect ShadowDepth="0"/>
</Border.Effect>
</Border>
</Border>
</Grid>
It's quite annoying, especially if working on custom control library.
The former and now apparently obsolete DropShadowBitmapEffect works on run- and designtime.
Edit:
This not a duplicate of other questions like Here as it is quite the opposite problem. The shadow effect appears at runtime, but not in the designer. Just try it out with NET-Framework WPF Project and the code above.

WPF DPI rendering issues with two borders

Enviroment
Win 8, VS 2012, .NET 4, WPF, screen native resolution 1920x1080#96DPI
XAML
<Border BorderThickness="1" BorderBrush="Red" Width="20" Height="20">
<Border BorderThickness="1" BorderBrush="Blue" />
</Border>
The problem
The borders look fine when DPI is 96, but if I change the DPI to 120, the borders are no longer perfectly pixel aligned.
What I have tried
1) Setting the following properties - RenderOptions.EdgeMode="Aliased" SnapsToDevicePixels="True" UseLayoutRounding="True" - on both borders, mitigates the anti-aliasing and bleeding issues from the higher DPI, but the inner border seems to have a 1px margin usually on the right and bottom sides.
2) The following code does not help to work around the problem:
<Grid Width="20" Height="20">
<Border BorderThickness="1" BorderBrush="Red" />
<Border BorderThickness="1" BorderBrush="Blue" Margin="1" />
</Grid>
3) Using Rectangles instead of Borders has the same problem.
4) The problem also persists under a guest Win 7 running in VirtualBox.
5) Edit - This looks a bit better, in that there is no inner margin, but the outer "border" is 2px thick:
<Canvas Width="20" Height="20">
<Polygon Points="0,0 20,0, 20,20, 0,20" StrokeThickness="1" Stroke="Red" RenderOptions.EdgeMode="Aliased" SnapsToDevicePixels="True" UseLayoutRounding="True" />
<Polygon Points="1,1 19,1, 19,19, 1,19" StrokeThickness="1" Stroke="Blue" RenderOptions.EdgeMode="Aliased" SnapsToDevicePixels="True" UseLayoutRounding="True" />
</Canvas>
Question(s)
How do I get the borders to be pixel perfect without any inner margins or anti-alising/bleeding?
I cannot use code-behind to rework the borders sizes when DPI is other than 96. I must stick to XAML only, because I'm trying to create vector icons (based on XAML).
Bravo Microsoft - https://connect.microsoft.com/VisualStudio/feedback/details/798513/wpf-dpi-rendering-issues-with-two-borders
Yet again, this issue will not be addressed nor fixed.

Good NumericUpDown equivalent in WPF? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I'm looking for a simple NumericUpDown (a.k.a. number spinner) control in WPF. This seems to be another lacking control in WPF. There must be some existing ones out there and I don't like to re-invent the wheel.
The Extended WPF Toolkit has one: NumericUpDown
A control that is missing from the original set of WPF controls, but much used, is the NumericUpDown control. It is a neat way to get users to select a number from a fixed range, in a small area. A slider could be used, but for compact forms with little horizontal real-estate, the NumericUpDown is essential.
Solution A (via WindowsFormsHost)
You can use the Windows Forms NumericUpDown control in WPF by hosting it in a WindowsFormsHost. Pay attention that you have to include a reference to System.Windows.Forms.dll assembly.
<Window x:Class="WpfApplication61.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<WindowsFormsHost>
<wf:NumericUpDown/>
</WindowsFormsHost>
...
Solution B (custom)
There are several commercial and codeplex versions around, but both involve installing 3rd party dlls and overheads to your project. Far simpler to build your own, and a aimple way to do that is with the ScrollBar.
A vertical ScrollBar with no Thumb (just the repeater buttons) is in fact just what we want. It inherits rom RangeBase, so it has all the properties we need, like Min, Max, and SmallChange (set to 1, to restrict it to Integer values)
So we change the ScrollBar ControlTemplate. First we remove the Thumb and Horizontal trigger actions. Then we group the remains into a grid and add a TextBlock for the number:
<Grid Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" FontSize="20" MinWidth="25" Text="{Binding Value, RelativeSource={RelativeSource TemplatedParent}}"/>
<Grid Grid.Column="1" x:Name="GridRoot" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition MaxHeight="18"/>
<RowDefinition Height="0.00001*"/>
<RowDefinition MaxHeight="18"/>
</Grid.RowDefinitions>
<RepeatButton x:Name="DecreaseRepeat" Command="ScrollBar.LineDownCommand" Focusable="False">
<Grid>
<Path x:Name="DecreaseArrow" Stroke="{TemplateBinding Foreground}" StrokeThickness="1" Data="M 0 4 L 8 4 L 4 0 Z"/>
</Grid>
</RepeatButton>
<RepeatButton Grid.Row="2" x:Name="IncreaseRepeat" Command="ScrollBar.LineUpCommand" Focusable="False">
<Grid>
<Path x:Name="IncreaseArrow" Stroke="{TemplateBinding Foreground}" StrokeThickness="1" Data="M 0 0 L 4 4 L 8 0 Z"/>
</Grid>
</RepeatButton>
</Grid>
</Grid>
Sources:
Is there a numericUpDown component in wpf?
WPF NumericUpDown from retemplating a ScrollBar
If commercial solutions are ok, you may consider this control set:
WPF Elements by Mindscape
It contains such a spin control and alternatively (my personal preference) a spin-decorator, that can decorate various numeric controls (like IntegerTextBox, NumericTextBox, also part of the control set) in XAML like this:
<WpfElements:SpinDecorator>
<WpfElements:IntegerTextBox Text="{Binding Foo}" />
</WpfElements:SpinDecorator>
add a textbox and scrollbar
in VB
Private Sub Textbox1_ValueChanged(ByVal sender As System.Object, ByVal e As System.Windows.RoutedPropertyChangedEventArgs(Of System.Double)) Handles Textbox1.ValueChanged
If e.OldValue > e.NewValue Then
Textbox1.Text = (Textbox1.Text + 1)
Else
Textbox1.Text = (Textbox1.Text - 1)
End If
End Sub

Radiobuttons and Silverlight

I have radiobutton in Silverlight 3 with FontSize=20.
Within the control the radio dialog image forced to the top alignment.
Relative to the text/content the image appears too high. This is not obvious with smaller text sizes however with the large text size the vertical alignment between the text/content and the dialog image looks ugly.
Any ideas on how to vertical-align = middle both the text and the dialog image?
ty
The image inside the RadioButton consists of several Ellipse elements grouped into a Grid element. If you take a look at the RadioButton template (use Expression Blend to edit a copy of the existing template) you will see that the Grid elements VerticalAlignment is set to Top.
<Grid HorizontalAlignment="Left" VerticalAlignment="Top">
<Ellipse x:Name="Background" Fill="#FFFFFFFF"
Stroke="{TemplateBinding BorderBrush}"
StrokeThickness="{TemplateBinding BorderThickness}"
Height="14" Margin="1" Width="14"/>
...
The ContentPresenters (where your text is displayed) VerticalAlignment is set to the value you set in the VerticalContentAlignment property.
<ContentPresenter x:Name="contentPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Grid.Column="1" Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"/>
To fix your problem you need to set the VerticalAlignment of the Grid element to Middle or use TemplateBinding to set it to the VerticalContentAlignment value.
<Grid HorizontalAlignment="Left"
VerticalAlignment="Middle">
OR
<Grid HorizontalAlignment="Left"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
It appears the best way is to use something like Padding="5,-7,0,0"

Resources