为什么WPF呈现两个完全相同的对象?
采取此窗口作为一个例子:为什么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>
这里是什么样的最终结果看上去像一个画面:
(该图片不适合100%,但您仍可以看到所有相关详情)。
在右边你可以看到NumericUpDowns的变焦项。最下面的那个看起来是正确的,但只是因为网格的行高被设置为自动。最上面的一个是扭曲的,但默认情况下,我希望它看起来与底部一样。
嗯...
我可能只是找到了一个可行的解决方案:
看来,通过设置ContentPresenter的保证金在我的NumericUpDown为“3,1”,一切看起来很完美。初步测试非常有希望,因为一切似乎都应该是这样......
我会测试它更多的明天,如果一切顺利将标记本的答案是正确的:)
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();
}
}
我希望这会有所帮助。
不知道为什么你看到这种行为,但这可能会解决它:尝试设置每个你的行数为.5 *,如果你有2行或者.25 *如果你有4行(或者.1 *如果你有10行,等等)。
将两行的行高设置为.5 *不起作用。 – Marko 2011-05-07 17:51:09
我同意本,但我会补充说,这种情况发生的另一个原因是因为你有SnapsToDevicePixels =“真”。通过设置这个,你告诉WPF你希望一切都在实际的像素边界上有一个边缘。既然你有一个偶数个项目,但奇数像素WPF必须使一个不同的大小,然后另一个。 – 2011-05-07 14:26:50
@Matt West你是真实的,但是我把它留给了我,因为我知道Marko知道SnapsToDevicePixels做什么,因为他把它设置在几乎所有东西上。 :) – Ben 2011-05-07 14:37:13
你是对的,通过将宽度设置为18,两个三角形的大小相同。但我不同意的是,因为宽度是17,高度也是17.实际上,第一个RepeatButton的高度是13px,第二个是12px。奇怪的是,如果我只是从两条多段线中删除Stretch =“Uniform”,那么它们都将是12px高。我已经设置了SnapToDevicePixels纯粹是为了尝试消除这种半像素舍入问题。如果我从所有元素中删除属性,那么最下面的按钮将变得更大...... – Marko 2011-05-07 17:44:40