2011-05-07 76 views
0

采取此窗口作为一个例子:为什么WPF呈现两个完全相同的对象?

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" ResizeMode="NoResize" SizeToContent="WidthAndHeight" SnapsToDevicePixels="True"> 
    <Grid Width="17" Margin="1"> 
     <Grid.RowDefinitions> 
      <RowDefinition /> 
      <RowDefinition /> 
     </Grid.RowDefinitions> 

     <RepeatButton Grid.Row="0" SnapsToDevicePixels="True"> 
      <Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="1" Fill="Red"> 
       <Polyline.Points> 
        <Point X="0" Y="3" /> 
        <Point X="3" Y="0" /> 
        <Point X="6" Y="3" /> 
       </Polyline.Points> 
      </Polyline> 
     </RepeatButton> 

     <RepeatButton Grid.Row="1" SnapsToDevicePixels="True"> 
      <Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="1" Fill="Red"> 
       <Polyline.Points> 
        <Point X="0" Y="3" /> 
        <Point X="3" Y="0" /> 
        <Point X="6" Y="3" /> 
       </Polyline.Points> 
      </Polyline> 
     </RepeatButton> 
    </Grid> 
</Window> 

一旦应用程序已经运行,最上面的的RepeatButton比底部高一个(因此顶三角形也比底部大一个)。为什么?
如果我创建4行相同RepeatButtons的,则1-ST和3-RD RepeatButtons大小相等的,并且比2次和第4次的RepeatButton更大?!?

我想这一定是在WPF布局系统的错误,但如何解决这个问题呢?我不能使用固定的高度(它可以解决问题),因为我需要RepeatButtons和三角形来扩展容器(我提供的示例只是为了显示问题而被简化,我知道我无法调整大小示例窗口...)。

编辑:

在回答Ben的评论:

是,随加风格的三角形做出来的9px和8像素高(我也可以同样通过了RepeatButtons产品总数,只留多边形作为网格的孩子,这会给出相同的结果)。因为三角形是等边,然后给电网17的宽度确实会引起高度,成为17为好,这当然是不够的,两个相等的高度三角形..

什么,我其实是想do是创建一个NumericUpDown控件。我发现默认情况下,17的微调器宽度和24的UserControl MinHeight看起来非常好。唯一的问题是,如果我把这个UserControl放到一个Grid中,那么最上面的三角形总是将它自身1px推到高处,破坏了外观。无论我如何试图与内部边距和填充混合,顶部的三角形总是会使自身比所需的高1px。所以实质上我想要的是有一个NumericUpDown,当放入一个网格时,不会扭曲自身。默认情况下,它应该看起来很完美(没有Grid RowHeight =“Auto”)并且正确缩放(没有固定的高度)。这一定是可能的,因为通过物理观察像素,一切都可以很好地适合给定的尺寸。

这里是我的NumericUpDown,我已经去掉了所有非必要的事情,使之更加紧凑:

<UserControl x:Class="HRS.NumericUpDown" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      MinWidth="40" MinHeight="24" Name="ucNUPD" Background="White" SnapsToDevicePixels="True"> 
    <UserControl.Resources> 
     <Style TargetType="{x:Type RepeatButton}"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="{x:Type RepeatButton}"> 
         <Border Name="borderOuter" BorderThickness="1" BorderBrush="Red"> 
          <Border Name="borderInner" BorderThickness="1" BorderBrush="Blue"> 
           <ContentPresenter Margin="2,1" /> 
          </Border> 
         </Border> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 

     <Style x:Key="triangleStyle" TargetType="{x:Type ContentControl}"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="{x:Type ContentControl}"> 
         <Polyline HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="Green" RenderOptions.EdgeMode="Aliased" Stretch="Uniform"> 
          <Polyline.Points> 
           <Point X="0" Y="3" /> 
           <Point X="3" Y="0" /> 
           <Point X="6" Y="3" /> 
          </Polyline.Points> 
         </Polyline> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </UserControl.Resources> 

    <Border BorderThickness="1" BorderBrush="#ABADB3"> 
     <DockPanel> 
      <UniformGrid Margin="1" DockPanel.Dock="Right" Rows="2" MinWidth="17" Width="17"> 
       <RepeatButton Name="repeatButtonUp" Grid.Row="0"> 
        <ContentControl Style="{StaticResource triangleStyle}" /> 
       </RepeatButton> 

       <RepeatButton Name="repeatButtonDown" Grid.Row="1"> 
        <ContentControl Style="{StaticResource triangleStyle}" RenderTransformOrigin="0.5, 0.5"> 
         <ContentControl.RenderTransform> 
          <ScaleTransform ScaleY="-1" /> 
         </ContentControl.RenderTransform> 
        </ContentControl> 
       </RepeatButton> 
      </UniformGrid> 

      <TextBox BorderThickness="0" VerticalContentAlignment="Center" Text="0" /> 
     </DockPanel> 
    </Border> 
</UserControl> 

这里是什么样的最终结果看上去像一个画面: Result

(该图片不适合100%,但您仍可以看到所有相关详情)。

在右边你可以看到NumericUpDowns的变焦项。最下面的那个看起来是正确的,但只是因为网格的行高被设置为自动。最上面的一个是扭曲的,但默认情况下,我希望它看起来与底部一样。

嗯...
我可能只是找到了一个可行的解决方案:
看来,通过设置ContentPresenter的保证金在我的NumericUpDown为“3,1”,一切看起来很完美。初步测试非常有希望,因为一切似乎都应该是这样......
我会测试它更多的明天,如果一切顺利将标记本的答案是正确的:)

回答

4

With SizeToContent =“WidthAndHeight”的高度将为17,因为您将网格的宽度设置为17。但是17/2 = 8.5,一行将为9(舍入因SnapsToDevicePixels =“True”而发生),但其他将会是8像素高。如果将宽度设置为18,则它们将相等。

证明我的理论:

<Grid Width="17" Margin="0"> 
<Grid.Resources> 
    <Style TargetType="{x:Type RepeatButton}"> 
    <Setter Property="BorderThickness" Value="0"/> 
    <Setter Property="Padding" Value="0"/> 
    <Setter Property="Margin" Value="0" /> 
    <Setter Property="Template"> 
     <Setter.Value> 
     <ControlTemplate TargetType="{x:Type ButtonBase}"> 
      <ContentPresenter Margin="0" 
           SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> 
     </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
    </Style> 
</Grid.Resources> 

<Grid.RowDefinitions> 
    <RowDefinition /> 
    <RowDefinition /> 
</Grid.RowDefinitions> 

<RepeatButton Grid.Row="0" SnapsToDevicePixels="True"> 
    <Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="0" Fill="Red"> 
    <Polyline.Points> 
     <Point X="0" Y="3" /> 
     <Point X="3" Y="0" /> 
     <Point X="6" Y="3" /> 
    </Polyline.Points> 
    </Polyline> 
</RepeatButton> 

<RepeatButton Grid.Row="1" SnapsToDevicePixels="True"> 
    <Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="0" Fill="Red"> 
    <Polyline.Points> 
     <Point X="0" Y="3" /> 
     <Point X="3" Y="0" /> 
     <Point X="6" Y="3" /> 
    </Polyline.Points> 
    </Polyline> 
</RepeatButton> 

在这个片段中,你获得一个三角形有9个像素高度,和一个8个像素。

但是,如果你想解决的办法试试这个:

<RepeatButton Grid.Row="1" SnapsToDevicePixels="True" Height="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth}" > 
    <Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="0" Fill="Red"> 
    <Polyline.Points> 
     <Point X="0" Y="3" /> 
     <Point X="3" Y="0" /> 
     <Point X="6" Y="3" /> 
    </Polyline.Points> 
    </Polyline> 
</RepeatButton> 

这样的宽度和按钮的高度将是相等的。

如果觉得你可以写一个小转换器也将可以做一些讨厌的东西:

<RepeatButton Grid.Row="1" SnapsToDevicePixels="True" Height="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={StaticResource TriangleWidthConverter}}" > 
    <Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="0" Fill="Red"> 
    <Polyline.Points> 
     <Point X="0" Y="3" /> 
     <Point X="3" Y="0" /> 
     <Point X="6" Y="3" /> 
    </Polyline.Points> 
    </Polyline> 
</RepeatButton> 

public class TriangleWidthConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
    int width = 0; 
    if (int.TryParse(value.ToString(), out width)) 
     return width + 1; // Do some fun here. 
    return value; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
    throw new NotImplementedException(); 
    } 
} 

我希望这会有所帮助。

+0

我同意本,但我会补充说,这种情况发生的另一个原因是因为你有SnapsToDevicePixels =“真”。通过设置这个,你告诉WPF你希望一切都在实际的像素边界上有一个边缘。既然你有一个偶数个项目,但奇数像素WPF必须使一个不同的大小,然后另一个。 – 2011-05-07 14:26:50

+0

@Matt West你是真实的,但是我把它留给了我,因为我知道Marko知道SnapsToDevicePixels做什么,因为他把它设置在几乎所有东西上。 :) – Ben 2011-05-07 14:37:13

+0

你是对的,通过将宽度设置为18,两个三角形的大小相同。但我不同意的是,因为宽度是17,高度也是17.实际上,第一个RepeatButton的高度是13px,第二个是12px。奇怪的是,如果我只是从两条多段线中删除Stretch =“Uniform”,那么它们都将是12px高。我已经设置了SnapToDevicePixels纯粹是为了尝试消除这种半像素舍入问题。如果我从所有元素中删除属性,那么最下面的按钮将变得更大...... – Marko 2011-05-07 17:44:40

0

不知道为什么你看到这种行为,但这可能会解决它:尝试设置每个你的行数为.5 *,如果你有2行或者.25 *如果你有4行(或者.1 *如果你有10行,等等)。

+0

将两行的行高设置为.5 *不起作用。 – Marko 2011-05-07 17:51:09

相关问题