I wrote a program to visualize the state of the keyboard. When I resize the window, the canvas in which I drew the rectangles keeps its size, but I want it to be resized to the window's size. I tried adding a SizeChanged
event handler for both the window and the canvas, but that didn't work.
I also tried to set the size of the Lights
canvas in the window's SizeChanged
event, but then the window filled almost the whole screen at startup.
So how can I reach the following goals?
- Initially, the client area of the window is 256 × 256.
- The window is resizable.
- When the window is resized, its content scales with it.
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);
}
}