为什么WPF以不同方式呈现两个相同的对象?

时间:2011-05-07 13:54:29

标签: 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-repeat RepeatButtons的大小相同,并且比第2和第4个RepeatButton大??

我认为这必定是WPF布局系统中的一个错误,但是如何解决这个问题呢?我不能使用固定的高度(这确实解决了问题),因为随着容器变大,我需要RepeatButtons和三角形strecth(我提供的示例简化为了显示问题,我知道我不能调整大小示例窗口...)。

编辑:

回复本的评论:

是的,添加的样式三角形确实出现了9px和8px高(我可以完全通过RepeatButtons,只留下折线作为网格子项,这将产生相同的结果)。因为三角形是相等的,所以给网格宽度为17确实会导致高度变为17,这对于两个相等高度的三角形当然是不够的。

我实际上要做的是创建一个NumericUpDown控件。我发现默认情况下,spinner宽度为17,UserControl MinHeight为24,看起来非常好。唯一的问题是,如果我将这个UserControl放入网格中,那么顶部三角形总是将自己的1px推高到高,破坏了外观。无论我如何尝试与内部边距和填充物混合,顶部三角形总是比自己的高1px。所以本质上我想要的是拥有一个NumericUpDown,当放入Grid时,它不会扭曲自己。默认情况下,它应该从get go(没有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的放大。底部看起来正确,但仅仅因为网格的行高度设置为自动。最上面的一个是扭曲的,但默认情况下我希望它看起来与底部完全一样。

嗯...
我可能刚刚找到了一个可行的解决方案:
似乎通过将NumericUpDown中ContentPresenter的Margin设置为“3,1”,一切看起来都很完美。初步测试是非常有希望的,因为一切看起来都应该是它应该的方式...
我会测试一下tommorow,如果一切顺利,将Ben的答案标记为正确:)

2 个答案:

答案 0 :(得分:4)

使用SizeToContent =“WidthAndHeight”,当你将Grid的宽度设置为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();
  }
}

我希望这些会有所帮助。

答案 1 :(得分:0)

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

相关问题