designing-wpf-customcontrol-architecture
1
总安装量
1
周安装量
#76168
全站排名
安装命令
npx skills add https://github.com/christian289/dotnet-with-claudecode --skill designing-wpf-customcontrol-architecture
Agent 安装分布
amp
1
cline
1
opencode
1
cursor
1
continue
1
kimi-cli
1
Skill 文档
XAML Code Writing – WPF CustomControl
A guide for using CustomControl and ResourceDictionary when writing XAML code in WPF.
Project Structure
The templates folder contains a WPF project example (use latest .NET per version mapping).
templates/
âââ WpfCustomControlSample.Controls/ â WPF Custom Control Library
â âââ Properties/
â â âââ AssemblyInfo.cs
â âââ Themes/
â â âââ Generic.xaml â MergedDictionaries hub
â â âââ CustomButton.xaml â Individual control style
â âââ CustomButton.cs
â âââ GlobalUsings.cs
â âââ WpfCustomControlSample.Controls.csproj
âââ WpfCustomControlSample.App/ â WPF Application
âââ Views/
â âââ MainWindow.xaml
â âââ MainWindow.xaml.cs
âââ App.xaml
âââ App.xaml.cs
âââ GlobalUsings.cs
âââ WpfCustomControlSample.App.csproj
Basic Principles
When generating XAML code, use CustomControl with Stand-Alone Control Style Resource through ResourceDictionary
Purpose: Fix the timing of StaticResource loading and minimize style dependencies
WPF Custom Control Library Project Structure
Default Structure When Creating Project
YourProject/
âââ Dependencies/
âââ Themes/
â âââ Generic.xaml
âââ AssemblyInfo.cs
âââ CustomControl1.cs
Restructure to Recommended Project Structure
YourProject/
âââ Dependencies/
âââ Properties/
â âââ AssemblyInfo.cs â Moved
âââ Themes/
â âââ Generic.xaml â Use as MergedDictionaries hub
â âââ CustomButton.xaml â Individual control style
â âââ CustomTextBox.xaml â Individual control style
âââ CustomButton.cs
âââ CustomTextBox.cs
Step-by-Step Setup
1. Create Properties Folder and Configure AssemblyInfo.cs
- Create Properties folder in the project
- Move AssemblyInfo.cs to the Properties folder
- Configure ThemeInfo attribute â See
/configuring-wpf-themeinfo
2. Configure Generic.xaml – Use as MergedDictionaries Hub
Generic.xaml does not define styles directly; it only performs the role of merging individual ResourceDictionaries:
<!-- Themes/Generic.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/YourProjectName;component/Themes/CustomButton.xaml" />
<ResourceDictionary Source="/YourProjectName;component/Themes/CustomTextBox.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
3. Define Individual Control Styles
Define styles in independent XAML files for each control:
<!-- Themes/CustomButton.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YourNamespace">
<!-- Control-specific resource definitions -->
<SolidColorBrush x:Key="ButtonBackground" Color="#FF2D5460" />
<SolidColorBrush x:Key="ButtonBackground_MouseOver" Color="#FF1D5460" />
<SolidColorBrush x:Key="ButtonForeground" Color="#FFFFFFFF" />
<!-- Control style definition -->
<Style TargetType="{x:Type local:CustomButton}">
<Setter Property="Background" Value="{StaticResource ButtonBackground}" />
<Setter Property="Foreground" Value="{StaticResource ButtonForeground}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomButton}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background"
Value="{StaticResource ButtonBackground_MouseOver}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Real Project Example
Generic.xaml Example
<!-- Themes/Generic.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/GameDataTool.Controls.Popup;component/Themes/GdtBranchSelectionPopup.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Individual Control Style Example
<!-- Themes/GdtBranchSelectionPopup.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GameDataTool.Controls.Popup"
xmlns:ui="clr-namespace:GameDataTool.Controls.GdtCore.UI;assembly=GameDataTool.Controls.GdtCore"
xmlns:unit="clr-namespace:GameDataTool.Controls.GdtUnits;assembly=GameDataTool.Controls.GdtUnits">
<SolidColorBrush x:Key="ApplyButtonBackground" Color="{DynamicResource Theme_PopupConfirmButtonColor}" />
<SolidColorBrush x:Key="ApplyButtonBackground_MouseOver" Color="#FF1D5460" />
<SolidColorBrush x:Key="ApplyButtonForeground" Color="{DynamicResource Theme_PopupConfirmButtonTextColor}" />
<SolidColorBrush x:Key="CancelButtonBackground" Color="#FFE8EBED" />
<SolidColorBrush x:Key="CancelButtonBackground_MouseOver" Color="#FFC9CDD2" />
<SolidColorBrush x:Key="CancelButtonForeground" Color="#FF323334" />
<Style TargetType="{x:Type local:GdtBranchSelectionPopup}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:GdtBranchSelectionPopup}">
<Border Width="{DynamicResource BranchSelectionPopupWidthSize}"
Height="{DynamicResource BranchSelectionPopupHeightSize}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<!-- Control content -->
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Advantages
- Each control’s style is separated into independent files for easier management
- Generic.xaml simply performs a merging role, making the structure clear
- StaticResource reference timing is clear and dependencies are minimized
- Work can be split by file for team collaboration