Why does WPF provide my diagonal split controls?

WPF seems to split my controls diagonally. What am I doing wrong? The problem is clearer on the blue button, but still noticeable on the one on the right.

alt textalt text

Unusually, kaxaml displays buttons correctly. A WPF designer never thinks. When I run the sample code in standalone "WpfApplication1", it displays correctly. However, inside my application I get a diagonal “cut”. It's probably worth mentioning that at run time, WPF doesn't seem to apply the slice effect, sometimes they render correctly!

Update 1: The Key! This applies only to the buttons! When I created a standalone Border and put a shortcut in its contents, no cutoff effect?!? !! So this is not xaml per se, but something magical to do with buttons ?! Thinking out loud, do something without completely overriding the default button template?

Update 2: Well, it gets even weirder every minute. This has something to do with the shadow effect. It seems that the first type of control that has an effect (BitmapEffect or wpf 4.0 Effect) is shared, like all other control instances of this type. For example, here is a DatePicker with a beautiful red shadow that splits the DatePicker control diagonally, the button after that is beautiful, despite the effect being applied to it.

alt text

If I do not apply the effect, no controls are separated. If I draw an effect control, this control will be split, and subsequent controls of different types will be accurate. However, if you have two or three controls of the same type, they are also separated. That is, if the button is divided, all buttons on the page will also be divided.

This should be related to my graphics or graphics drivers. I updated them this morning, but without joy. (I am using Radeon Mobility HD 5650, v 8.683.2.0). If this problem is isolated only from my PC, I believe that this is not the end of the world. Perhaps I can defeat him in my own game by drawing a transparent effect on a random pixel path at the top of each page or something like that.

Update 3

Oh my God. I played it on another PC now, so this is not my video card or drivers.

  <StackPanel.Resources> <!-- Background for button when IsDefault true"--> <LinearGradientBrush x:Key="DefaultButtonFill" StartPoint="0.5, 0" EndPoint="0.5, 1"> <GradientStop Color="#FFDFEDEC" Offset="0"/> <GradientStop Color="#FF92B1E3" Offset="0.4"/> <GradientStop Color="#FF749EE0" Offset="0.5"/> <GradientStop Color="#94DDF6" Offset="1"/> </LinearGradientBrush> <!-- default button background --> <LinearGradientBrush x:Key="NotDefaultButtonFill" StartPoint="0.5, 0" EndPoint="0.5, 1"> <GradientStop Color="#FFEFEFF5" Offset="0"/> <GradientStop Color="#FFE1E1E6" Offset="0.4"/> <GradientStop Color="#FFC7CBD0" Offset="0.5"/> <GradientStop Color="#FFE8ECEE" Offset="1"/> </LinearGradientBrush> <Style TargetType="Button"> <Setter Property="FontSize" Value="14"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Border x:Name="border" CornerRadius="12" Background="{StaticResource NotDefaultButtonFill}" Padding="25 8" Margin="10" Cursor="Hand"> <Border.BitmapEffect> <DropShadowBitmapEffect x:Name="shadow" Direction="280" Color="Black" ShadowDepth="2" Opacity=".6"/> </Border.BitmapEffect> <!-- <Border.Effect> <DropShadowEffect x:Name="shadow" Direction="280" Color="Black" ShadowDepth="2" Opacity=".6"/> </Border.Effect>--> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}" /> </Border> <ControlTemplate.Triggers> <Trigger Property="IsDefault" Value="True"> <Setter TargetName="border" Property="Background" Value="{StaticResource DefaultButtonFill}"/> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="border" Property="Background" Value="LightGray"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </StackPanel.Resources> <StackPanel Orientation="Horizontal"> <Button>Normal</Button> <Button IsDefault="True">IsDefault</Button> </StackPanel> </StackPanel> 
+7
source share
5 answers

This is due to an error caused by some subtle interaction between WPF and ATI graphics drivers. Apparently, this happens when using DropShadowEffect for elements that do not fit on pixel borders.

If you set UseLayoutRounding = "True" for the items in question (or in the appropriate style), which seems to fix the problem in many cases, although not for everyone. Another thing is to make sure that you do not intentionally position elements in half the pixels (for example, using fractional fields, this can happen if you move elements around in Expression Blend).

Here is a simple example:

  <UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <UserControl.Resources> <Style x:Key="ButtonStyle" TargetType="{x:Type Button}"> <Setter Property="Width" Value="28"/> <Setter Property="Height" Value="28"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Button}"> <Border x:Name="Border" Background="Transparent"> <Grid Margin="{TemplateBinding Padding}"> <ContentPresenter x:Name="contentPresenter" VerticalAlignment="Center" HorizontalAlignment="Center"> <ContentPresenter.Effect> <DropShadowEffect BlurRadius="13" Color="Black" Opacity="1" ShadowDepth="0" Direction="0"/> </ContentPresenter.Effect> </ContentPresenter> </Grid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </UserControl.Resources> <Grid> <Button x:Name="MinimizeButton" Style="{StaticResource ButtonStyle}"> <Rectangle x:Name="MinimizeIcon" Width="11" Height="2" HorizontalAlignment="Center" Margin="0,7,0,0" VerticalAlignment="Bottom" Stroke="Gray" StrokeThickness="2"/> </Button> </Grid> </UserControl> 

If you put this in Kaxaml and move the zoom slider, you will see that the split appears when the scale is set to 150.

If you add the <Setter Property="UseLayoutRounding" Value="True"/> style to the button style, a zoom level of 150 will display correctly, but a split will appear at a zoom level of 300.

That's why I say that my work does not work in all cases - if you need to display only content with a fixed size, UseLayoutRounding can hide a problem of this size, but if you have the zoom function in your application, you can still get the problem at times .

From the Microsoft Forums , here is what ATI had to say about the problem:

The main reason is that WPF 4.0 will use DX10-style texture coordinate addressing to render text with a dot filter (round to nearest) when using the DX9 API. We follow the DX9 rule (Truncate to nearest), as it is a DX9 driver. If we force our HW to use DX10 style texture coordinates, the problem will disappear. However, Microsoft Ithink should follow its own rule, use the DX9 texture to coordinate coordinates when using the DX9 API.

If you can also reproduce this problem, go ahead and add your vote to the question I added to Connect so that we can get it fixed - although I don't really hope so; Microsoft joined in on a similar issue , saying that they find work acceptable for the time being.

+3
source

The main problem arises when WPF has an effect on a tree having a partial pixel offset. There are two main approaches that we could take for the hardware path:

1) Create an intermediate texture that matches the pixels on the screen and render the tree with a partial pixel offset inside that texture. Then, when we transfer this intermediate element back to the screen, we can use pixel-aligned quadrants and use a simple selection of the nearest neighbor, because the content is pixel-aligned.

2) Create an intermediate texture that matches the borders of the tree and render the tree at offset 0 inside this texture. Then, when moving the intermediate element back to the screen, we need to use a square that covers partial pixels. Since the quadrant can span partial pixels, sampling is very important. Sampling modes, such as NearestNeighbor, can cause anti-aliasing artifacts, which can be GPU dependent.

WPF chose # 2 and forcibly chose the closest neighbor sample - if only a tree that had no transformation other than an offset or scale (most often a rotation), in this case it forced a bilinear selection. This is subtly different from the software rasterization path, which will use the interpolation mode valid for the tree, unless the tree had a transformation other than offset or scale, in which case it also forcibly took a bilinear sample.

We "fix" this problem by bringing the hardware path in line with the software path. This means that we will refer to the sampling mode in effect for the displayed tree. This can be set from managed code with the RenderOptions.BitmapScalingMode property attached. The default value is Linear, which is a more acceptable sampling mode when the square covers partial pixels. However, it introduces a noticeable blur - but the same thing as software rasterization.

There are several ways in 4.0:

1) Prohibit the location of the element tree on a partial pixel. For example, you can set the UseLayoutRounding property to true in containers that position the item with the effect.

2) Apply a little rotation to force the rendering path to use bilinear interpolation. It can be very small, for example, RenderTransform with <RotateTransform Angle="0.00000000001"/>

Note that custom ShaderEffects use explicit samplers with custom sampling modes.

Clients will be able to get the current behavior by setting the attached RenderOptions.BitmapScalingMode property to "NearestNeighbor". Note that even this will be ignored if the tree is rotated and bilinear sampling will be used instead. It remains true that on some GPUs, effects like DropShadow can occur with anti-aliasing artifacts when using the NearestNeighbor selection.

Also note that when applying an effect to an image, the same value of the property of the attached property RenderOptions.BitmapScalingMode will be used both for the image content and for the intermediate texture of the effect. If you want to get an image using NearestNeighbor selection, but the effect of using linear selection, you will need to apply the effect to the image container, for example, to a simple canvas containing the image.

+3
source

Try organizing the attachment as follows:

 <StackPanel Orientation="Horizontal"> <StackPanel.Resources> ... </StackPanel.Resources> <Button>Normal</Button> <Button IsDefault="True">IsDefault</Button> </StackPanel> 
0
source

If this is a designer, you cannot do much. The diagonal is very similar to splitting a rectangle into two triangles for rendering on the GPU. This may be caused by the designer or video card driver. This may be a simple rounding error.

Does this show the designer at all levels of scaling?

0
source

I found a workaround to the problem. This workaround doesn't make sense, but it looks like the splicing effect is going away.

In short, my application is a tabbed interface (MDI). I have a tabcontrol style that contains all the other controls in my application. In the strip strip, I have a stylized button that creates a new tab (another style from splicing buttons).

If I remove the specialist’s style from the “add tab” button, leaving it by default, the splicing effect will disappear from other buttons in my application. Both button styles are stored in the same ResourceDictionary, which is combined in my app.xaml ResourceDictionary. This may be the key, but I cannot understand its meaning.

In addition, if I insert a style label into the strip of tabs in front of the add tab button, the splicing effect disappears regardless of the style of the add tab button. If I just add a shortcut without a style name, the splicing effect will return.

Neither the label nor the add button ever show a splicing effect. However, by changing their styles, it controls whether the splicing effect appears on other buttons.

I can only conclude that this is a bug in WPF because I cannot come up with a decent reason why changing the style on one control should have any effect on the other rendering of the controls.

0
source

All Articles