A lightweight library that automatically saves and restores WPF window positions and states between application sessions.
- Automatic window placement persistence - Save and restore window position, size, and state
- Registry-based storage - Built-in storage using Windows Registry
- Extensible storage - Implement custom storage strategies (JSON, XML, database, etc.)
- Simple XAML integration - Add with a single line of code
- Zero dependencies - Pure WPF implementation
- .NET 5.0-windows, 6.0-windows, 7.0-windows, 8.0-windows
Install via NuGet Package Manager:
Install-Package AutoWindowPlacement.WPFOr via .NET CLI:
dotnet add package AutoWindowPlacement.WPFAdd the namespace to your Window XAML:
<Window x:Class="YourApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:awp="https://github.com/nullsoftware/AutoWindowPlacement.WPF"
awp:WindowExtensions.PlacementStorageStrategy="{awp:RegistryStorage}"
Title="Main Window" Height="450" Width="800">
<!-- Your window content -->
</Window>That's it! The window position and state will now be automatically saved to the Windows Registry and restored on next launch.
The simplest way to use AutoWindowPlacement is with the built-in RegistryStorage:
<Window xmlns:awp="https://github.com/nullsoftware/AutoWindowPlacement.WPF"
awp:WindowExtensions.PlacementStorageStrategy="{awp:RegistryStorage}">
</Window>By default, this stores window placement in:
HKEY_CURRENT_USER\SOFTWARE\{CompanyName}\{ProductName}\{WindowName}.Placement
Customize the registry key and naming format:
<Window awp:WindowExtensions.PlacementStorageStrategy="{awp:RegistryStorage
Key='SOFTWARE\\MyCompany\\MyApp\\WindowSettings',
NameFormat='{0}_Position'}">
</Window>Implement the IWindowPlacementStorage interface for custom storage:
using System.Windows;
using NullSoftware.Windows;
public class JsonFileStorage : IWindowPlacementStorage
{
private readonly string _filePath;
public JsonFileStorage(string filePath)
{
_filePath = filePath;
}
public byte[]? LoadPlacement(Window window)
{
// Load from JSON file
// Return byte array or null if not found
}
public void SavePlacement(Window window, byte[] serializedPlacement)
{
// Save to JSON file
}
}Then use it in code-behind:
public MainWindow()
{
InitializeComponent();
WindowExtensions.SetPlacementStorageStrategy(this, new JsonFileStorage("settings.json"));
}The main class providing attached properties for window placement.
PlacementStorageStrategy- Gets or sets the storage strategy for window placement
WindowExtensions.SetPlacementStorageStrategy(window, storageInstance);
IWindowPlacementStorage storage = WindowExtensions.GetPlacementStorageStrategy(window);Interface for implementing custom storage strategies.
public interface IWindowPlacementStorage
{
void SavePlacement(Window window, byte[] serializedPlacement);
byte[]? LoadPlacement(Window window);
}Built-in implementation that stores window placement in Windows Registry.
Hive- Registry hive (default:RegistryHive.CurrentUser)Key- Registry key path (default:SOFTWARE\{Company}\{Product})NameFormat- Value name format (default:{0}.Placement)
GetSettingKey(Window)- Override to customize the registry value nameProvideDefaultHive()- Override to change default registry hiveProvideDefaultKey()- Override to change default registry key path
Low-level API for direct window placement manipulation.
// Get window placement
var placement = WindowPlacementManager.GetPlacement(window);
// Set window placement
WindowPlacementManager.SetPlacement(window, placement);
// Serialize placement to bytes
byte[] data = WindowPlacementManager.Serialize(placement);
// Deserialize placement from bytes
var placement = WindowPlacementManager.Deserialize(data);<Window awp:WindowExtensions.PlacementStorageStrategy="{awp:RegistryStorage
Key='SOFTWARE\\MyApp\\Settings',
Hive='CurrentUser'}">
</Window>public MainWindow()
{
InitializeComponent();
if (Settings.Default.RememberWindowPosition)
{
WindowExtensions.SetPlacementStorageStrategy(this, new RegistryStorage());
}
}public class CustomRegistryStorage : RegistryStorage
{
protected override string GetSettingKey(Window window)
{
// Use window title instead of type name
return string.Format(NameFormat, window.Title.Replace(" ", "_"));
}
protected override string ProvideDefaultKey()
{
return @"SOFTWARE\MyCompany\MyApp\Windows";
}
}- When
PlacementStorageStrategyis set, the library hooks into window events - On
SourceInitialized, it loads the saved placement and applies it to the window - On
Closing, it captures the current placement and saves it via the storage strategy - Window placement includes: position, size, and state (normal/maximized/minimized)
The library automatically detects design-time mode and disables itself in the Visual Studio designer, ensuring a smooth design experience.
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
Developed by Null Software