Почему WPF рендерит мои элементы управления с диагональным разделением? - PullRequest
7 голосов
/ 14 января 2011

WPF, кажется, разделяет мои элементы управления по диагонали.Что я делаю неправильно?Проблема проясняется на синей кнопке, но все же заметна на правой.

alt text alt text

Как ни странно, kaxaml правильно отображает кнопки.Дизайнер WPF никогда не кажется.Когда я запускаю пример кода в автономном «WpfApplication1», он отображается правильно.Однако внутри моего приложения я получаю диагональный «разрез».Вероятно, стоит упомянуть, что во время выполнения WPF, похоже, последовательно не применяет эффект среза, иногда они отображаются правильно!

Обновление 1: Подсказка!Это только влияющих на кнопки!Когда я создал автономный Border и поместил метку в качестве содержимого, никакого эффекта среза?!? !!Так что это не сам xaml, а что-то волшебное в кнопках ?!Размышляя вслух, что-то делать, если не полностью переопределить шаблон кнопки по умолчанию?

Обновление 2: Ну, с каждой минутой это становится еще более странным.Это как-то связано с эффектом тени.Похоже, что первый нарисованный элемент управления, который имеет эффект (BitmapEffect или wpf 4.0 Effect), разделен, как и все другие экземпляры элемента управления этого типа.Например, вот DatePicker с прекрасной красной тенью, которая разбивает элемент управления DatePicker по диагонали, после этого кнопка работает нормально, несмотря на то, что к ней также применен эффект.

alt text

Если я не применяю эффект, никакие элементы управления не разделяются.Если я рисую элемент управления с эффектом, этот элемент управления будет разделен, и последующие элементы управления различных типов будут в порядке.Однако, если у вас есть два или три элемента управления одного типа, они тоже разделяются.То есть, если кнопка разделена, все кнопки на странице также будут разделены.

Это должно быть как-то связано с моим GPU или графическими драйверами.Я обновил их сегодня утром, но не радости.(Я использую Radeon Mobility HD 5650, v 8.683.2.0).Если эта проблема связана только с моим ПК, я полагаю, что это не конец света.Возможно, я смогу победить его в своей собственной игре, нарисовав эффект прозрачности в произвольном пикселе Path вверху каждой страницы или что-то в этом роде ...

Обновление 3

О, Боже.Я воспроизвел это на другом ПК сейчас, так что это не моя видеокарта или драйверы.

        <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>

Ответы [ 5 ]

3 голосов
/ 22 декабря 2011

Основная проблема возникает, когда WPF создает эффект для дерева с частичным смещением пикселей. Есть два основных подхода, которые мы могли бы сделать для аппаратного пути:

1) Создайте промежуточную текстуру, соответствующую пикселям экрана, и визуализируйте дерево с частичным смещением в пределах этой текстуры. Затем при переносе этого промежуточного элемента обратно на экран мы можем использовать выровненные по пикселям квадраты и использовать простую выборку ближайших соседей, поскольку содержимое выровнено по пикселям.

2) Создайте промежуточную текстуру, которая соответствует границам дерева, и визуализируйте дерево с нулевым смещением в пределах этой текстуры. Затем при переносе промежуточного изображения обратно на экран нам нужно использовать квад, который покрывает частичные пиксели. Поскольку квад может покрывать частичные пиксели, важен режим выборки. Режимы выборки, такие как NearestNeighbor, могут вызывать артефакты сглаживания, которые могут зависеть от графического процессора.

WPF выбрал # 2 и принудительную выборку ближайшего соседа - если только дерево, у которого было какое-либо преобразование, кроме смещения или масштаба (чаще всего вращения), в этом случае не принудительно использовало билинейную выборку. Это несколько отличается от пути растеризации программного обеспечения, который будет использовать режим интерполяции, действующий для дерева, если только дерево не имеет преобразования, отличного от смещения или масштаба, и в этом случае оно также принудительно вызывает билинейную выборку.

Мы «исправляем» эту проблему, приводя аппаратный путь в соответствие с программным путем. Это означает, что мы будем уважать действующий режим выборки для визуализируемого дерева. Это можно установить из управляемого кода с помощью вложенного свойства RenderOptions.BitmapScalingMode. Значением по умолчанию является Линейный, что является более подходящим режимом выборки, когда квадратор покрывает частичные пиксели. Тем не менее, он вносит заметную размытость - но так же, как и растеризация программного обеспечения.

Для 4.0 есть несколько обходных путей:

1) Не допускайте расположения дерева элементов на частичном пикселе. Например, вы можете установить для свойства UseLayoutRounding значение true для контейнеров, которые позиционируют элемент с эффектом.

2) Примените небольшое вращение, чтобы заставить путь рендеринга использовать билинейную интерполяцию. Это может быть очень мало, например, RenderTransform с <RotateTransform Angle="0.00000000001"/>

Обратите внимание, что пользовательские эффекты ShaderEffects используют явные сэмплеры с настраиваемыми режимами сэмплирования.

Клиенты смогут узнать текущее поведение, установив для присоединенного свойства RenderOptions.BitmapScalingMode значение "NearestNeighbor". Обратите внимание, что даже это будет игнорироваться, если дерево вращается, и вместо этого будет использоваться билинейная выборка. Остается верным, что на некоторых графических процессорах такие эффекты, как DropShadow, могут сталкиваться с артефактами сглаживания при использовании выборки NearestNeighbor.

Также обратите внимание, что при применении эффекта к изображению одно и то же значение присоединенного свойства RenderOptions.BitmapScalingMode будет использоваться как для содержимого изображения, так и для промежуточной текстуры эффекта. Если вам нужно изображение с выборкой NearestNeighbor, но с эффектом, использующим линейную выборку, вам потребуется применить эффект к контейнеру изображения, такому как простой холст, содержащий изображение.

3 голосов
/ 24 октября 2011

Это связано с ошибкой, вызванной некоторым тонким взаимодействием между графическими драйверами WPF и ATI.Кажется, это происходит при использовании DropShadowEffect на элементах, которые не совсем расположены на границах пикселей.

Если вы установите UseLayoutRounding = "True" для рассматриваемых элементов (или в соответствующем стиле), который, кажется, исправляетпроблема во многих случаях, хотя и не во всех.Еще нужно убедиться, что вы не намеренно размещаете элементы на полпикселях (например, с использованием дробных полей - это может произойти, если вы перемещаете элементы в Expression Blend).

Вот простое повторениеcase:

 <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>

Если вы вставите это в Kaxaml и передвинете ползунок масштабирования, вы увидите, что разделение появляется, когда масштабирование установлено на 150.

Если вы добавите <Setter Property="UseLayoutRounding" Value="True"/> к стилю кнопки, уровень масштабирования 150 будет отображаться правильно, но разделение будет отображаться на уровне масштабирования 300.

Именно поэтому я говорю, что мой обходной путь работает не во всех случаях -если вам нужно отображать содержимое только в одном фиксированном размере, UseLayoutRounding может скрыть проблему с этим размером, но если в вашем приложении есть функция масштабирования, вы все равно можете иногда ее решить.

Из Форумы Microsoft , вот что ATI должна была сказать по этому вопросу:

Основная причина заключается в том, что WPF 4.0 будет использовать адресацию текстурных координат в стиле DX10визуализировать текст с точечным фильтром (с округлением до ближайшего) при использовании DX9 API.Мы следуем правилу DX9 (от усечения до ближайшего), так как это драйвер DX9.Если мы принудительно используем наши координаты текстуры в стиле DX10, проблема исчезнет.Однако я думаю, что Microsoft должна следовать своему собственному правилу, использовать координатную адресацию текстуры в стиле DX9 при использовании DX9 API. "

Если вы можете воспроизвести и эту проблему, перейдите и добавьте свой голос к проблеме IМы добавили в Connect , чтобы мы могли это исправить - хотя я не очень надеюсь, Microsoft отреагировала на аналогичную проблему , сказав, что они считают обходной путь приемлемым на то время.бытия.

0 голосов
/ 15 января 2011

Если это только дизайнер, мало что можно сделать. Диагональ очень похожа на расщепление прямоугольника на два треугольника, поскольку рендеринг на графическом процессоре неверен. Это может быть вызвано дизайнером или драйвером видеокарты. Это может быть простая ошибка округления.

Показывает ли он все уровни масштабирования дизайнера?

0 голосов
/ 18 января 2011

Я нашел решение этой проблемы. Этот обходной путь не имеет смысла, но, похоже, устраняет эффект сращивания.

Вкратце, мое приложение представляет собой интерфейс с вкладками (MDI). У меня есть стиль tabcontrol, который содержит все другие элементы управления в моем приложении. В закладке у меня есть стилизованная кнопка, которая создает новую вкладку (стиль, отличный от склеенных кнопок).

Если я удаляю стилистику специалиста с кнопки «Добавить вкладку», оставляя ее со стилем по умолчанию, эффект сращивания уходит от других кнопок в моем приложении. Оба стиля кнопок хранятся в одном и том же ResourceDictionary, который объединен с моим app.xaml ResourceDictionary. Возможно, это ключ, но я не могу понять его значение.

Кроме того, если я вставлю метку со стилем в полосу вкладок перед кнопкой «Добавить вкладку», эффект сращивания пропадет независимо от стиля кнопки «Добавить вкладку». Если я просто добавлю метку без именованного стиля, эффект сращивания вернется.

Кажется, что ни метка, ни кнопка добавления вкладки не дают эффекта сращивания. Однако, изменяя их стили, контролирует, появляется ли эффект сращивания на других кнопках.

Я могу только заключить, что это ошибка в WPF, потому что я не могу придумать причину, по которой изменение стиля на одном элементе управления должно влиять на рендеринг другого элемента управления.

0 голосов
/ 15 января 2011

Попробуйте организовать вложение следующим образом:

<StackPanel Orientation="Horizontal">
   <StackPanel.Resources>
      ...
   </StackPanel.Resources>
   <Button>Normal</Button>
   <Button IsDefault="True">IsDefault</Button>
</StackPanel>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...