【问题标题】:Resizable WPF window with fixed initial size具有固定初始大小的可调整大小的 WPF 窗口
【发布时间】:2016-08-12 06:02:22
【问题描述】:

我编写了一个程序来可视化键盘的状态。当我调整窗口大小时,绘制矩形的画布保持其大小,但我希望将其调整为窗口大小。我尝试为窗口和画布添加SizeChanged 事件处理程序,但没有奏效。

我还尝试在窗口的SizeChanged 事件中设置Lights 画布的大小,但随后窗口在启动时几乎填满了整个屏幕。

那么我怎样才能达到以下目标呢?

  • 最初,窗口的客户区为 256 × 256。
  • 窗口可调整大小。
  • 调整窗口大小时,其内容会随之缩放。

MainWindow.xaml

<Window x:Class="KeyMonitor.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Key Monitor" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen" ResizeMode="CanResize">
    <Grid>
        <Canvas x:Name="Lights" Width="256" Height="256" />
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace KeyMonitor
{
    public partial class MainWindow : Window
    {
        private Rectangle[] indicators = new Rectangle[256];

        public MainWindow()
        {
            InitializeComponent();

            for (int i = 0; i < 256; i++)
                Lights.Children.Add(indicators[i] = new Rectangle { Fill = Brushes.Transparent });

            Lights.SizeChanged += Lights_SizeChanged;

            var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(100) };
            timer.Tick += Timer_Tick;
            timer.Start();
        }

        private void Lights_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            //Lights.Width = e.NewSize.Width;
            //Lights.Height = e.NewSize.Height;
            for (int y = 0; y < 16; y++)
            {
                var sy = (int)(e.NewSize.Height * y / 16);
                var sy1 = (int)(e.NewSize.Height * (y + 1) / 16);

                for (int x = 0; x < 16; x++)
                {
                    var sx = (int)(e.NewSize.Width * x / 16);
                    var sx1 = (int)(e.NewSize.Width * (x + 1) / 16);

                    var indicator = indicators[16 * y + x];
                    indicator.Width = 1 + sx1 - sx;
                    indicator.Height = 1 + sy1 - sy;
                    Canvas.SetLeft(indicator, sx);
                    Canvas.SetTop(indicator, sy);
                }
            }
        }

        void Timer_Tick(object sender, EventArgs e)
        {
            var keys = new byte[256];
            if (User32.GetKeyboardState(keys) != 0)
            {
                for (int i = 0; i < 256; i++)
                {
                    var r = (byte)((keys[i] & 0x7E) != 0 ? 0xFF : 0x00);
                    var g = (byte)((keys[i] & 0x01) != 0 ? 0xFF : 0x00);
                    var b = (byte)((keys[i] & 0x80) != 0 ? 0xFF : 0x00);
                    indicators[i].Fill = new SolidColorBrush(Color.FromRgb(r, g, b));
                }
            }
        }
    }

    static class User32
    {
        [DllImport("user32")]
        public static extern int GetKeyboardState(byte[] lpKeyState);
    }
}

【问题讨论】:

    标签: c# wpf


    【解决方案1】:

    要缩放内容,请将画布放在视图框内。这将适当地缩放内容。

        <ViewBox>
    <Canvas x:Name="Lights" />
    </ViewBox>
    

    【讨论】:

    • 这很好地解决了我的一半问题,即调整画布大小。但它不能解决初始窗口大小。初始窗口大约占屏幕的一半,而不是 256 × 256 的区域。
    【解决方案2】:

    我会将 Window 的大小设置为初始 256*256 并让 Canvas 在其中拉伸:

    <Window x:Class="KeyMonitor.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Key Monitor" Width="256" Height="256" 
            WindowStartupLocation="CenterScreen" >
        <!-- Grid is not necessary-->
        <Canvas x:Name="Lights" />
    </Window>
    

    HorizointalAlignmentVerticalAlignment 的默认值为 Stretch,因此无需设置其他属性。

    默认的调整大小模式已经是CanResize,所以也没有必要。我还删除了SizeToContent 值,因为默认值是Manual,这就是您需要的。

    编辑:我发现初始大小有一点问题。在 xaml 中设置WidthHeight 表示包含Windows 添加的边框的大小。所以如果Height=Width 内容大小不是正方形。
    我在 SO 上找到了解决方案:How to set WPF window's startup ClientSize?。总是使用后面的代码并不是最好的,但我认为这是一个合理的解决方法。并且只针对初始大小。

    【讨论】:

    • 这几乎正是我想要的。唯一缺少的是窗口客户区的初始大小。奇怪的是,在 Visual Studio 设计器中,包含标题栏和边框的窗口是 256 × 256,但是当我运行应用程序时,窗口只有 242 × 249。
    • @RolandIllig 你说得对,我能够重现这个问题。我进行了一些研究,并在另一个 SO 线程上找到了一个可行的解决方案。我在答案中链接到它。
    • @RolandIllig 您可以设置内容大小使用SizeToContent属性。
    • @heltonbiker 这行不通。如果您设置 Canvas 的大小或其父级的大小,则 Canvas 在更改大小时不会调整到窗口的大小。
    猜你喜欢
    • 1970-01-01
    • 2012-12-13
    • 1970-01-01
    • 2011-02-13
    • 2018-04-20
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 2011-06-04
    相关资源
    最近更新 更多