2010-11-05 86 views
0

我在WPF上比較新,我需要一些幫助。WPF:防止邊界厚度縮放

我在ViewBox上有一個ViewBox,裏面有一個Ellipse和一個邊框。 當我調整窗體大小時,我想讓橢圓和邊框自動縮放(它的功能)。 但我不想讓BorderThickness縮放。邊框的厚度應保持3像素。

有誰知道如何做到這一點?

這是我的XAML:

<Window 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
x:Class="StretchTest.MainWindow" 
x:Name="Window" 
Title="MainWindow" 
Width="700" Height="400"> 

<Grid x:Name="LayoutRoot"> 
    <Viewbox> 
     <Grid Height="300" Width="400" HorizontalAlignment="Center" VerticalAlignment="Center"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="*"/> 
       <RowDefinition Height="*"/> 
       <RowDefinition Height="*"/> 
      </Grid.RowDefinitions> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="*"/> 
       <ColumnDefinition Width="*"/> 
       <ColumnDefinition Width="*"/> 
       <ColumnDefinition Width="*"/> 
      </Grid.ColumnDefinitions> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="0" Grid.Column="0"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="0" Grid.Column="0"/> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="0" Grid.Column="1"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="0" Grid.Column="1"/> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="0" Grid.Column="2"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="0" Grid.Column="2"/> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="0" Grid.Column="3"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="0" Grid.Column="3"/> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="1" Grid.Column="0"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="1" Grid.Column="0"/> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="1" Grid.Column="1"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="1" Grid.Column="1"/> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="1" Grid.Column="2"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="1" Grid.Column="2"/> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="1" Grid.Column="3"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="1" Grid.Column="3"/> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="2" Grid.Column="0"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="2" Grid.Column="0"/> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="2" Grid.Column="1"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="2" Grid.Column="1"/> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="2" Grid.Column="2"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="2" Grid.Column="2"/> 
      <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="2" Grid.Column="3"/> 
      <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="2" Grid.Column="3"/> 
     </Grid> 
    </Viewbox> 
</Grid> 

感謝您的幫助!

回答

0

我會建議不要使用ViewBox。如果您不設置橢圓和邊框的寬度和高度,它們將自動與窗口一起確定大小。代替使用網格使用行高和列寬的百分比來設定控制的相對大小(例如0.6 *)


更新 - 實施例

<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="0.4*" /> 
     <ColumnDefinition Width="0.6*" /> 
    </Grid.ColumnDefinitions> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="*" /> 
     <RowDefinition Height="Auto" /> 
    </Grid.RowDefinitions> 

    <Border Grid.Row="1" Name="border1" BorderBrush="Black" BorderThickness="1" Padding="2"> 
     <Ellipse Name="ellipse1" Stroke="Black" Grid.Row="1" Stretch="UniformToFill" /> 
    </Border> 
</Grid> 

更新

嗯,沒有看到一個簡單的方法來完成你所需要的。下面是我能夠來的最近的。 唯一的其他選擇,我可以看到:

  1. 將每個橢圓在它自己的視圖框
  2. 尺寸網格列&行代碼的窗口大小調整

    <Grid HorizontalAlignment="Center" VerticalAlignment="Center"> 
        <Grid.RowDefinitions> 
         <RowDefinition Height="Auto"/> 
         <RowDefinition Height="Auto"/> 
         <RowDefinition Height="Auto"/> 
         <RowDefinition Height="*"/> 
        </Grid.RowDefinitions> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="*"/> 
        </Grid.ColumnDefinitions> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="0" Grid.Column="0" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="0" Grid.Column="0"/> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="0" Grid.Column="1" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="0" Grid.Column="1"/> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="0" Grid.Column="2" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="0" Grid.Column="2"/> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="0" Grid.Column="3" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="0" Grid.Column="3"/> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="1" Grid.Column="0" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="1" Grid.Column="0"/> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="1" Grid.Column="1" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="1" Grid.Column="1"/> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="1" Grid.Column="2" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="1" Grid.Column="2"/> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="1" Grid.Column="3" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="1" Grid.Column="3"/> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="2" Grid.Column="0" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="2" Grid.Column="0"/> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="2" Grid.Column="1" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="2" Grid.Column="1"/> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="2" Grid.Column="2" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="2" Grid.Column="2"/> 
        <Ellipse Fill="#FF7171EB" Stroke="#FF041374" StrokeThickness="3" Grid.Row="2" Grid.Column="3" Stretch="UniformToFill"/> 
        <Border BorderBrush="Red" BorderThickness="3" CornerRadius="8" Grid.Row="2" Grid.Column="3"/> 
    </Grid> 
    
+0

<BorderyViewbox x:Name="Viewbox"> <Border BorderBrush="Red" SnapsToDevicePixels="True"> <Border.BorderThickness> <Binding Path="Scale" ElementName="Viewbox" Converter="{x:Static BorderyViewbox.ThicknessConverter}"> <Binding.ConverterParameter> <Thickness>3</Thickness> </Binding.ConverterParameter> </Binding> </Border.BorderThickness> </Border> </BorderyViewbox> 

使用靜態資源較短的版本謝謝你的建議Thomas。 問題是橢圓和邊框應拉伸=均勻。只有BorderThickness不應該。如果我將Ellipse和Border放置在一個網格單元格中,我如何指定網格應拉伸=均勻? – Jackerd 2010-11-06 20:38:52

+0

我已經給我的答案添加了一個例子,希望它可以幫助 – Thomas 2010-11-07 03:32:11

+0

謝謝托馬斯,我檢查了你的例子,但它不完全是我需要的。我設法在我的問題中添加了我的XAML。行爲正是我所需要的,但只有BorderThickness不應該伸展。 – Jackerd 2010-11-07 09:10:04

0

作爲替代解決方案(如果稍後有人會發現此問題)以防止邊框厚度縮放,則可以使用具有特殊轉換器的自定義版本的Viewbox。

平時Viewbox控件,但現在有一個只讀Scale性能和靜態ThicknessConverter

public class BorderyViewbox : Decorator { 
    public static readonly DependencyProperty StretchProperty = DependencyProperty.Register(nameof(Stretch), 
      typeof(Stretch), typeof(BorderyViewbox), new FrameworkPropertyMetadata(Stretch.Uniform, FrameworkPropertyMetadataOptions.AffectsMeasure)); 

    public Stretch Stretch { 
     get { return (Stretch)GetValue(StretchProperty); } 
     set { SetValue(StretchProperty, value); } 
    } 

    public static readonly DependencyProperty StretchDirectionProperty = DependencyProperty.Register(nameof(StretchDirection), 
      typeof(StretchDirection), typeof(BorderyViewbox), new FrameworkPropertyMetadata(StretchDirection.Both, FrameworkPropertyMetadataOptions.AffectsMeasure)); 

    public StretchDirection StretchDirection { 
     get { return (StretchDirection)GetValue(StretchDirectionProperty); } 
     set { SetValue(StretchDirectionProperty, value); } 
    } 

    public static readonly DependencyPropertyKey ScalePropertyKey = DependencyProperty.RegisterReadOnly(nameof(Scale), typeof(Size), 
      typeof(BorderyViewbox), new PropertyMetadata(default(Size))); 

    public static readonly DependencyProperty ScaleProperty = ScalePropertyKey.DependencyProperty; 

    public Size Scale => (Size)GetValue(ScaleProperty); 

    private ContainerVisual InternalVisual { 
     get { 
      if (_internalVisual == null) { 
       _internalVisual = new ContainerVisual(); 
       AddVisualChild(_internalVisual); 
      } 
      return _internalVisual; 
     } 
    } 

    private UIElement InternalChild { 
     get { 
      var vc = InternalVisual.Children; 
      return vc.Count != 0 ? vc[0] as UIElement : null; 
     } 
     set { 
      var vc = InternalVisual.Children; 
      if (vc.Count != 0) vc.Clear(); 
      vc.Add(value); 
     } 
    } 

    private Transform InternalTransform { 
     get { return InternalVisual.Transform; } 
     set { InternalVisual.Transform = value; } 
    } 

    public override UIElement Child { 
     get { return InternalChild; } 
     set { 
      var old = InternalChild; 
      if (!ReferenceEquals(old, value)) { 
       RemoveLogicalChild(old); 

       if (value != null) { 
        AddLogicalChild(value); 
       } 

       InternalChild = value; 
       InvalidateMeasure(); 
      } 
     } 
    } 

    protected override int VisualChildrenCount => 1; 

    protected override Visual GetVisualChild(int index) { 
     if (index != 0) throw new ArgumentOutOfRangeException(nameof(index)); 
     return InternalVisual; 
    } 

    protected override IEnumerator LogicalChildren => InternalChild == null ? EmptyEnumerator.Instance : new SingleChildEnumerator(InternalChild); 

    protected override Size MeasureOverride(Size constraint) { 
     var child = InternalChild; 
     var parentSize = new Size(); 

     if (child != null) { 
      var infinteConstraint = new Size(double.PositiveInfinity, double.PositiveInfinity); 

      child.Measure(infinteConstraint); 
      var childSize = child.DesiredSize; 

      var scale = ComputeScaleFactor(constraint, childSize, Stretch, StretchDirection); 
      SetValue(ScalePropertyKey, scale); 

      parentSize.Width = scale.Width * childSize.Width; 
      parentSize.Height = scale.Height * childSize.Height; 
     } 

     return parentSize; 

    } 

    protected override Size ArrangeOverride(Size arrangeSize) { 
     var child = InternalChild; 
     if (child != null) { 
      var childSize = child.DesiredSize; 

      var scale = ComputeScaleFactor(arrangeSize, childSize, Stretch, StretchDirection); 
      SetValue(ScalePropertyKey, scale); 

      InternalTransform = new ScaleTransform(scale.Width, scale.Height); 
      child.Arrange(new Rect(new Point(), child.DesiredSize)); 

      arrangeSize.Width = scale.Width * childSize.Width; 
      arrangeSize.Height = scale.Height * childSize.Height; 
     } 
     return arrangeSize; 
    } 

    private static Size ComputeScaleFactor(Size availableSize, Size contentSize, Stretch stretch, StretchDirection stretchDirection) { 
     var scaleX = 1.0; 
     var scaleY = 1.0; 

     var isConstrainedWidth = !double.IsPositiveInfinity(availableSize.Width); 
     var isConstrainedHeight = !double.IsPositiveInfinity(availableSize.Height); 

     if ((stretch == Stretch.Uniform || stretch == Stretch.UniformToFill || stretch == Stretch.Fill) 
       && (isConstrainedWidth || isConstrainedHeight)) { 
      scaleX = Equals(0d, contentSize.Width) ? 0.0 : availableSize.Width/contentSize.Width; 
      scaleY = Equals(0d, contentSize.Height) ? 0.0 : availableSize.Height/contentSize.Height; 

      if (!isConstrainedWidth) { 
       scaleX = scaleY; 
      } else if (!isConstrainedHeight) { 
       scaleY = scaleX; 
      } else { 
       switch (stretch) { 
        case Stretch.Uniform: 
         var minscale = scaleX < scaleY ? scaleX : scaleY; 
         scaleX = scaleY = minscale; 
         break; 

        case Stretch.UniformToFill: 
         var maxscale = scaleX > scaleY ? scaleX : scaleY; 
         scaleX = scaleY = maxscale; 
         break; 

        case Stretch.Fill: 
         break; 
       } 
      } 

      switch (stretchDirection) { 
       case StretchDirection.UpOnly: 
        if (scaleX < 1.0) scaleX = 1.0; 
        if (scaleY < 1.0) scaleY = 1.0; 
        break; 

       case StretchDirection.DownOnly: 
        if (scaleX > 1.0) scaleX = 1.0; 
        if (scaleY > 1.0) scaleY = 1.0; 
        break; 

       case StretchDirection.Both: 
        break; 
      } 
     } 

     return new Size(scaleX, scaleY); 
    } 

    private ContainerVisual _internalVisual; 

    #region Converter-related stuff 
    private class ConverterInner : IValueConverter { 
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { 
      if (!(value is Size)) return parameter; 

      var scale = (Size)value; 
      var thickness = parameter as Thickness? ?? new Thickness(1d); 

      return new Thickness(thickness.Left/scale.Width, thickness.Top/scale.Height, 
        thickness.Right/scale.Width, thickness.Bottom/scale.Height); 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { 
      if (!(value is Size)) return parameter; 

      var scale = (Size)value; 
      var thickness = parameter as Thickness? ?? new Thickness(1d); 

      return new Thickness(thickness.Left * scale.Width, thickness.Top * scale.Height, 
        thickness.Right * scale.Width, thickness.Bottom * scale.Height); 
     } 
    } 

    public static IValueConverter ThicknessConverter { get; } = new ConverterInner(); 
    #endregion 

} 

用例:

<Thickness x:Key="BorderThickness">3</Thickness> 

<BorderyViewbox x:Name="Viewbox"> 
    <Border BorderBrush="Red" SnapsToDevicePixels="True" 
      BorderThickness="{Binding Path=Scale, ElementName=Viewbox, 
        Converter={x:Static BorderyViewbox.ThicknessConverter}, 
        ConverterParameter={StaticResource BorderThickness}}" /> 
</BorderyViewbox>