zoukankan      html  css  js  c++  java
  • 利用WPF建立自适应窗口大小布局的WinForm窗口

    编写WinForm程序时,都会碰到一个问题。就是WinForm窗口在不同分辨率下的大小问题。举例说明,你编写的WinForm窗口在1024×768下是合适、匀称的。不过,如果用户的计算机的分辨率为1400×900时,你的WinForm窗口就显得偏小,其中的字体和控件都显得偏小。如果用户的分辨率为640×480,那你的窗口就远远超过它的屏幕的大小。

      如何解决这个问题?一般的WinForm程序都会这样操作:程序启动——》获取屏幕分辨率——》调整窗体的大小——》调整各个控件大小及位置——》调整各个控件的字体。这样操作比较繁琐,并且要考虑到各种分辨率的情况。这样一来,如果WinForm窗口上有若干控件,调整是一件很痛苦的事。

      有没有这样的手段。我只要调整WinForm窗口的大小,其中的各个控件大小(包括字体)自动的等比例缩放?

      还记得一些DirectX的游戏程序吗?当设定为固定的分辨率时(比如800×600),在全屏的时候,他都会自动缩放。WinForm有这样的手段吗?

      答案是肯定的。在WPF中就能很简单的实现该功能。

      利用WPF中的ViewBox容器空间。ViewBox是一个容器空间,它会自动缩放容器中的子空间以填满自身,同时它只能有一个子控件。不过,我们可以把Canvas控件作为ViewBox控件的子控件。然后在Canvas控件中布局其他的控件。

      先看看下面的窗口的Xaml文件

      <Window x:Class="Window1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="WPFTest"

        mc:Ignorable="d"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        SizeToContent="Manual" Width="400" Height="300">
        <DockPanel Name="DockPanel1" LastChildFill="True">
          <Menu Height="23" Name="Menu1" DockPanel.Dock="Top">
            <MenuItem Header="Menu1">
              <MenuItem Header="H1" />
              <MenuItem Header="H2" />
            </MenuItem>
              <MenuItem Header="Menu2">
              <MenuItem Header="L1" />
              <MenuItem Header="L2" />
              <Separator />
              <MenuItem Header="L4" />
            </MenuItem>
          </Menu>
          <StatusBar Height="23" Name="StatusBar1" DockPanel.Dock="Bottom">
            <StatusBarItem Content="S1" Name="S1"/>
            <StatusBarItem Content="S2" Name="S2"/>
            <StatusBarItem Content="S3" Name="S3"/>
          </StatusBar>
          <Viewbox Name="Viewbox1" Stretch="Fill">
            <Canvas Height="200" Name="Canvas1" Width="300" Background="#FF8EDE75">
              <Button Canvas.Left="43" Canvas.Top="40" Content="Button" Height="37" Name="Button1" Width="87" />
            </Canvas>
          </Viewbox>
        </DockPanel>
      </Window>

      先简单的说明这个XAML文件

      最外面的是Window容器,设置了标题(WPFTest)和大小(400×300),它也只能有一个子控件。

      Window的子控件是DockPanel容器,是自动停靠容器控件。设置LastChildFill="True",表示最后一个子控件自动填充剩余的空间。没有设置大小,默认大小是Window的客户区大小。

      DockPanel控件有三个子控件

        Menu控件:菜单控件,自动停靠在容器的顶端

        StatusBar控件:状态栏控件,自动停靠在容器的底部

        ViewBox控件:容器控件,自动填充DockPanel剩余的控件。没有设置大小,为填充的大小。设置填充的模式为Fill,表示子控件填充自身的容器的大小

          在ViewBox中放置了一个Canvas控件,设置了大小(注:一定要设置大小,否则默认时会产生各种不可思议的效果),设置了背景色

          在Canvas中放置了一个Button控件。只是示例,Canvas中还能放置其他的控件

      在Window的代码中输入如下的代码

      Public Class Window1

        Private _I As Integer
        Private Sub Window1_SizeChanged(ByVal sender As Object, ByVal e As System.Windows.SizeChangedEventArgs) Handles Me.SizeChanged
          _I += 1
          Me.S1.Content = "窗口宽度:" & Me.Width
          Me.S2.Content = "内容宽度:" & Me.Viewbox1.Width
          Me.S3.Content = "按钮宽度:" & Me.Button1.Width & ";刷新次数:" & _I

        End Sub

      End Class

      

      启动后是如下的效果

      

      可以看出窗口的宽度是400,由于ViewBox没有设置宽度,故显示非数字,按钮的宽度是87

      拖动右下角,调整Window的大小。如下图所示

       

      和上图的比较,Window的大小发生了变化。ViewBox中的子控件也自动的拉伸了。这个从Button的外观能很明显的感受到。更神奇的是,无论我怎么调整Window的大小,Button的外观也随着Window的大小而改变,不过,在内部的逻辑中,Button的宽度始终是87,始终没有发生变化。

      另,由于Menu和StatusBar不在ViewBox内。故这两个控件没有缩放,还是原始的大小

      这给我们带来了极大的便利。无论window被调整到如何,在内部逻辑中,ViewBox中的子控件Canvas的逻辑大小始终是300×200。我们不需要再为调整后的大小设计额外的代码。

      实际上,我猜测。ViewBox的显示机制是,先在内存中把按照逻辑大小把子控件显示出来,然后等比例的缩放显示到ViewBox的客户区。

      回到开始的话题。编写的WinForm窗口如何应对不同的分辨率?

      在WPF中,将所有的客户控件放在Canvas中再放在ViewBox控件中,利用ViewBox的特性来实现自动的缩放。流程就变成了:程序启动——》获取屏幕分辨率——》调整窗体的大小。其余控件的缩放就交给ViewBox控件吧。而且由于逻辑的大小没有发生变化,你还不必要再额外添加代码。

      网上ViewBox控件介绍的比较少,用ViewBox来实现自适应窗体的大小确是独辟蹊径。

  • 相关阅读:
    智能推荐算法演变及学习笔记(三):CTR预估模型综述
    从中国农业银行“雅典娜杯”数据挖掘大赛看金融行业数据分析与建模方法
    智能推荐算法演变及学习笔记(二):基于图模型的智能推荐(含知识图谱/图神经网络)
    (设计模式专题3)模板方法模式
    (设计模式专题2)策略模式
    (设计模式专题1)为什么要使用设计模式?
    关于macOS上常用操作命令(持续更新)
    记录下关于RabbitMQ常用知识点(持续更新)
    EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
    SpringCloud教程二:Ribbon(Finchley版)
  • 原文地址:https://www.cnblogs.com/wpf123/p/2073140.html
Copyright © 2011-2022 走看看