我是WPF的新手,我需要一些帮助。
我在ViewBox上有一个ViewBox,一个是椭圆和一个边框。 当我调整表单大小时,我希望椭圆和边框自动缩放(它的作用)。 但我不希望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 :(得分: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>
<强>更新强>
嗯,没有看到一个简单的方法来完全按照你的需要做。以下是我能来的最接近的。 我能看到的唯一其他选择:调整网格列的大小&amp;窗口调整大小的代码行
<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>
答案 1 :(得分:0)
作为替代解决方案(如果稍后有人会发现此问题)以防止BorderThickness缩放,您可以使用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
}
用法示例:
<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>
使用静态资源的较短版本:
<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>
答案 2 :(得分:0)
解决方案是拆分内容和边框。完成后,从视图框内部通过绑定将边框的宽度和高度设置为grid ActualWidth和Height:
<Grid>
<Viewbox>
<Border
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}, Path=ActualWidth}"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}, Path=ActualHeight}"
Background="{StaticResource TcsFilledColor}"
BorderBrush="{StaticResource TcsBaseColor}"
BorderThickness="10">
</Border>
</Viewbox>
<Viewbox>
<Label
Padding="10"
Style="{StaticResource BaseLabelStyle}">
<TextBlock
Style="{StaticResource BaseTextBlockStyle}"
Text="{Binding SomeText, FallbackValue=SomeText}" />
</Label>
</Viewbox>
</Grid>
希望这会有所帮助;)