2011-05-07 70 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

相關問題