【问题标题】:How to scale controls with maintained aspect ratio and position without viewbox?如何在没有视图框的情况下在保持纵横比和位置的情况下缩放控件?
【发布时间】:2023-04-06 21:19:01
【问题描述】:

我正在尝试在 显示设置 中复制显示 rearranger UI,其中有相对于其物理位置放置的按钮,并且可以通过鼠标拖动重新排列

我可以从屏幕类中获取屏幕边界

System.Windows.Forms.Screen

并在画布中创建具有指定边界的按钮,但它们太大(即 1366 x 768)无法在容器中显示,因此我决定使用 WPF 的内置 ViewBox 控件

viewbox 的问题在于它不仅可以缩放边界,还可以缩放渲染元素

我无法控制 BorderThicknessFontSizeMargin,当画布尺寸为改变了。

我需要的只是缩放大小,而不是全部。我希望边界厚度具有固定大小,而不是缩放。在设置之一中,按钮的 BorderThickness 即使在调整大小后也保持不变。无论我尝试什么,我都会得到这个>

这里Button的大小为1366 x 768,边框厚度为1 px(看不清楚,我必须设置为4 px才能清楚),字体大小为240 px。

此按钮托管在画布中,其大小以编程方式确定,画布托管在边框中的视图框中。我应该怎么做才能缩放大小?

【问题讨论】:

  • 为什么不使用实际屏幕尺寸的固定比例创建按钮,例如1366 x 768 屏幕的 137 x 77 按钮?
  • 我可以这样做,但是当屏幕超过 2 个时,它应该自行缩小而不是溢出。 (我不希望滚动条出现在那里)我希望它们根据它们的位置放置,如果我按比例缩小它们(例如 10)我还需要缩放它们的位置。我不知道如何找到一个固定因素来缩小它们:(

标签: .net wpf canvas scale viewbox


【解决方案1】:

我终于实现了,我摆脱了viewbox并设法通过代码做到了

代码:

    Private Sub LoadScreens()
        Dim ox As Integer = 0
        Dim oy As Integer = 0
        Dim canvaswidth As Integer = 0
        Dim canvasheight As Integer = 0
        Dim rect As New List(Of System.Drawing.Rectangle)
        For i = 0 To Forms.Screen.AllScreens.Count - 1
            Dim screen = Forms.Screen.AllScreens(i)
            Dim r = screen.Bounds
            rect.Add(r)
        Next
        For Each r In rect
            If r.X < ox Then ox = r.X
            If r.Y < oy Then oy = r.Y
        Next
        For Each r In rect
            If r.X + r.Width + Math.Abs(ox) > canvaswidth Then canvaswidth = r.X + r.Width + Math.Abs(ox)
            If r.Y + r.Height + Math.Abs(oy) > canvasheight Then canvasheight = r.Y + r.Height + Math.Abs(oy)
        Next

        ScreenCanvas.Children.Clear()

        Dim scale = GetScale(TParent.ActualWidth, TParent.ActualHeight, canvaswidth, canvasheight)

        ScreenCanvas.Width = canvaswidth * scale
        ScreenCanvas.Height = canvasheight * scale

        For i = 0 To rect.Count - 1
            Dim r = rect(i)
            Dim left = (r.X - ox) * scale
            Dim top = (r.Y - oy) * scale
            Dim nr As New Primitives.ToggleButton With {
                .Width = r.Width * scale,
                .Height = r.Height * scale,
                .Content = New TextBlock() With {.Text = i + 1, .VerticalAlignment = VerticalAlignment.Center, .HorizontalAlignment = HorizontalAlignment.Center}
            }
            ScreenCanvas.Children.Add(nr)
            Canvas.SetLeft(nr, left)
            Canvas.SetTop(nr, top)
        Next
    End Sub

    Private Function GetScale(w1 As Double, h1 As Double, w2 As Double, h2 As Double) As Double
        Dim scaleHeight = h1 / h2
        Dim scaleWidth = w1 / w2
        Dim scale = Math.Min(scaleHeight, scaleWidth)
        Return scale
    End Function

ToggleButtons 以编程方式创建、缩放、定位并添加到缩放的画布:ScreenCanvas,它托管在 TParent 网格中。

XAML:

          <Border CornerRadius="10" Margin="40" Padding="40" Background="#22aaaaaa">
            <Grid x:Name="TParent" Height="150" >
                <Grid.Resources>
                    <Style TargetType="{x:Type ToggleButton}">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type ToggleButton}">
                                    <Border Background="White" BorderBrush="Red" BorderThickness="2">
                                        <ContentPresenter TextBlock.Foreground="Black"/>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </Grid.Resources>
                <Canvas x:Name="ScreenCanvas" HorizontalAlignment="Center"  VerticalAlignment="Bottom"/>
            </Grid>
        </Border>

这是最终结果:

现在我可以控制borderthickness、cornerradius、margin :)

编辑:

我更新了 UI 并添加了代码,以便在更改网格大小时更新它们的位置和大小。

代码:

     Private Sub TParent_SizeChanged(sender As Object, e As SizeChangedEventArgs) Handles TParent.SizeChanged
        If e.WidthChanged AndAlso _init Then
            Dim canvaswidth = ScreenCanvas.ActualWidth
            Dim canvasheight = ScreenCanvas.ActualHeight
            Dim scale = GetScale(TParent.ActualWidth, TParent.ActualHeight, canvaswidth, canvasheight)
            ScreenCanvas.Width = canvaswidth * scale
            ScreenCanvas.Height = canvasheight * scale
            For Each c As FrameworkElement In ScreenCanvas.Children
                c.Width = c.ActualWidth * scale
                c.Height = c.ActualHeight * scale
                Dim top = Canvas.GetTop(c) * scale
                Dim left = Canvas.GetLeft(c) * scale
                Canvas.SetTop(c, top)
                Canvas.SetLeft(c, left)
            Next
        End If
    End Sub

用户界面:

【讨论】:

    猜你喜欢
    • 2018-04-29
    • 2017-04-12
    • 2012-06-19
    • 1970-01-01
    • 2016-05-17
    • 2013-07-18
    • 1970-01-01
    • 2021-07-21
    • 2018-06-12
    相关资源
    最近更新 更多