固定初始大小的可调整大小的WPF窗口

固定初始大小的可调整大小的WPF窗口

问题描述:

我编写了一个程序来可视化键盘的状态。当我调整窗口大小时,绘制矩形的画布保持其大小,但我希望将其调整为窗口大小。我试图为窗口和画布添加一个SizeChanged事件处理程序,但那不起作用。固定初始大小的可调整大小的WPF窗口

我也尝试在窗口的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); 
    } 
} 

我将设置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?。这是不是最好的总是使用代码背后,但我认为这是一个合理的解决方法。这只是初始大小。

+0

这几乎就是我想要的。唯一缺少的是窗口_client area_的初始大小。奇怪的是,在Visual Studio设计器中,包含标题栏和边框的窗口为256×256,但是当我运行该应用程序时,该窗口仅为242×249. –

+0

@RolandIllig您说得对,我能够重现此问题。我花了一点研究,并找到另一个SO线程的工作解决方案。我在我的答案中将其链接到它。 – Koopakiller

+0

@RolandIllig你可以设置内容大小_and_使用'SizeToContent'属性。 – heltonbiker

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

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

这很好地解决了我的一半问题,即调整画布大小。但它不能解决初始窗口大小。初始窗口大约填满了一半的屏幕,而不是256×256的区域。 –