WinUI 3 WinRT C++ 开发完整教程 - 第五部分:XAML框架与数据绑定深层机制
XAML 编译和解析机制
XAML 编译流程详解
XAML 不是在运行时解析的,而是在编译时被转换为 C++ 代码。让我们深入了解这个过程:
1. XAML 编译器的工作原理
xml
<!-- MainWindow.xaml 原始文件 -->
<Window x:Class="WinUI3App1C__.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Button x:Name="myButton" Content="点击我" Click="myButton_Click"/>
</Grid>
</Window>
编译器会生成对应的 C++ 代码(MainWindow.g.h):
cpp
// MainWindow.g.h (简化版)
namespace winrt::WinUI3App1C__::implementation
{
template<typename D>
struct MainWindowT : DependencyObjectT<D>
{
private:
bool _contentLoaded = false;
// XAML 中定义的控件的成员变量
winrt::Microsoft::UI::Xaml::Controls::Button _myButton{nullptr};
public:
void InitializeComponent()
{
if (_contentLoaded)
return;
_contentLoaded = true;
// 创建根元素 (Grid)
auto grid = winrt::Microsoft::UI::Xaml::Controls::Grid{};
// 创建按钮
_myButton = winrt::Microsoft::UI::Xaml::Controls::Button{};
_myButton.Content(winrt::box_value(L"点击我"));
// 绑定事件处理器
_myButton.Click({this, &MainWindow::myButton_Click});
// 添加到父容器
grid.Children().Append(_myButton);
// 设置为窗口内容
Content(grid);
}
// 访问 XAML 控件的方法
winrt::Microsoft::UI::Xaml::Controls::Button myButton()
{
return _myButton;
}
};
}
2. x:Name 的实现机制
当你在 XAML 中写 x:Name="myButton"
时,编译器会:
- 生成私有成员变量:
_myButton
- 生成公共访问方法:
myButton()
- 在 InitializeComponent 中初始化:创建对象并赋值
cpp
// 理解为什么可以在 C++ 代码中直接使用 myButton()
void MainWindow::SomeMethod()
{
// 这个调用实际上是调用生成的访问方法
myButton().Content(winrt::box_value(L"新内容"));
// 等价于访问私有成员 _myButton
// _myButton.Content(winrt::box_value(L"新内容")); // 直接访问会编译错误
}
3. 事件绑定的生成机制
XAML 中的 Click="myButton_Click"
会被编译器转换为:
cpp
// 在 InitializeComponent 中生成的代码
_myButton.Click({this, &implementation::MainWindow::myButton_Click});
// 这需要你在 .h 文件中声明对应的方法:
void myButton_Click(
winrt::Windows::Foundation::IInspectable const& sender,
winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
XAML 命名空间映射
1. 默认命名空间
xml
<!-- 默认命名空间包含所有基础 UI 控件 -->
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Button/> <!-- Microsoft.UI.Xaml.Controls.Button -->
<TextBox/> <!-- Microsoft.UI.Xaml.Controls.TextBox -->
</Window>
这个 URL 映射到:
winrt::Microsoft::UI::Xaml::Controls::
winrt::Microsoft::UI::Xaml::
- 其他相关命名空间
2. XAML 命名空间 (x:)
xml
<Window xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button x:Name="myButton"/> <!-- 指定名称 -->
<Grid x:FieldModifier="public"/><!-- 修改字段访问性 -->
</Window>
3. 自定义命名空间映射
xml
<!-- 映射到项目中的自定义类型 -->
<Window xmlns:local="using:WinUI3App1C__">
<local:CustomControl/> <!-- 使用自定义控件 -->
</Window>
对应的 C++ 命名空间:
cpp
namespace winrt::WinUI3App1C__::implementation
{
struct CustomControl : CustomControlT<CustomControl>
{
// 自定义控件实现
};
}
依赖属性系统深度解析
依赖属性的底层实现
依赖属性是 WinUI 3 的核心特性,支持数据绑定、动画、样式等功能:
1. 依赖属性的内部结构
cpp
// 简化的依赖属性系统实现
class DependencyPropertySystem
{
private:
// 全局属性注册表
static std::unordered_map<winrt::guid, std::unique_ptr<PropertyMetadata>> s_properties;
// 每个对象的属性值存储
std::unordered_map<winrt::Microsoft::UI::Xaml::DependencyProperty, winrt::Windows::Foundation::IInspectable> m_localValues;
public:
// 注册依赖属性
static winrt::Microsoft::UI::Xaml::DependencyProperty Register(
hstring const& name,
winrt::Windows::UI::Xaml::Interop::TypeName const& propertyType,
winrt::Windows::UI::Xaml::Interop::TypeName const& ownerType,
winrt::Microsoft::UI::Xaml::PropertyMetadata const& metadata);
// 获取属性值
winrt::Windows::Foundation::IInspectable GetValue(
winrt::Microsoft::UI::Xaml::DependencyProperty const& property);
// 设置属性值
void SetValue(
winrt::Microsoft::UI::Xaml::DependencyProperty const& property,
winrt::Windows::Foundation::IInspectable const& value);
};
2. 创建自定义依赖属性
让我们创建一个完整的依赖属性示例:
cpp
// CustomControl.idl
namespace WinUI3App1C__
{
[default_interface]
runtimeclass CustomControl : Microsoft.UI.Xaml.Controls.UserControl
{
CustomControl();
// 声明依赖属性
static Microsoft.UI.Xaml.DependencyProperty TitleProperty{ get; };
String Title;
static Microsoft.UI.Xaml.DependencyProperty ValueProperty{ get; };
Double Value;
}
}
cpp
// CustomControl.h
namespace winrt::WinUI3App1C__::implementation
{
struct CustomControl : CustomControlT<CustomControl>
{
private:
// 静态依赖属性字段
static winrt::Microsoft::UI::Xaml::DependencyProperty s_titleProperty;
static winrt::Microsoft::UI::Xaml::DependencyProperty s_valueProperty;
public:
CustomControl();
// 依赖属性访问器
static winrt::Microsoft::UI::Xaml::DependencyProperty TitleProperty() { return s_titleProperty; }
hstring Title() const;
void Title(hstring const& value);
static winrt::Microsoft::UI::Xaml::DependencyProperty ValueProperty() { return s_valueProperty; }
double Value() const;
void Value(double value);
private:
// 属性变更回调
static void OnTitlePropertyChanged(
winrt::Microsoft::UI::Xaml::DependencyObject const& d,
winrt::Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs const& e);
static void OnValuePropertyChanged(
winrt::Microsoft::UI::Xaml::DependencyObject const& d,
winrt::Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs const& e);
};
}
cpp
// CustomControl.cpp
namespace winrt::WinUI3App1C__::implementation
{
// 注册依赖属性
winrt::Microsoft::UI::Xaml::DependencyProperty CustomControl::s_titleProperty =
winrt::Microsoft::UI::Xaml::DependencyProperty::Register(
L"Title", // 属性名称
winrt::xaml_typename<hstring>(), // 属性类型
winrt::xaml_typename<winrt::WinUI3App1C__::CustomControl>(), // 拥有者类型
winrt::Microsoft::UI::Xaml::PropertyMetadata{
winrt::box_value(L""), // 默认值
&OnTitlePropertyChanged // 变更回调
});
winrt::Microsoft::UI::Xaml::DependencyProperty CustomControl::s_valueProperty =
winrt::Microsoft::UI::Xaml::DependencyProperty::Register(
L"Value",
winrt::xaml_typename<double>(),
winrt::xaml_typename<winrt::WinUI3App1C__::CustomControl>(),
winrt::Microsoft::UI::Xaml::PropertyMetadata{
winrt::box_value(0.0),
&OnValuePropertyChanged
});
CustomControl::CustomControl()
{
InitializeComponent();
}
// 属性访问器实现
hstring CustomControl::Title() const
{
return winrt::unbox_value<hstring>(GetValue(s_titleProperty));
}
void CustomControl::Title(hstring const& value)
{
SetValue(s_titleProperty, winrt::box_value(value));
}
double CustomControl::Value() const
{
return winrt::unbox_value<double>(GetValue(s_valueProperty));
}
void CustomControl::Value(double value)
{
SetValue(s_valueProperty, winrt::box_value(value));
}
// 属性变更回调
void CustomControl::OnTitlePropertyChanged(
winrt::Microsoft::UI::Xaml::DependencyObject const& d,
winrt::Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs const& e)
{
if (auto control = d.try_as<winrt::WinUI3App1C__::implementation::CustomControl>())
{
// 处理 Title 属性变更
hstring oldValue = winrt::unbox_value<hstring>(e.OldValue());
hstring newValue = winrt::unbox_value<hstring>(e.NewValue());
OutputDebugStringW((L"Title 从 '" + oldValue + L"' 变更为 '" + newValue + L"'\n").c_str());
}
}
void CustomControl::OnValuePropertyChanged(
winrt::Microsoft::UI::Xaml::DependencyObject const& d,
winrt::Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs const& e)
{
if (auto control = d.try_as<winrt::WinUI3App1C__::implementation::CustomControl>())
{
// 处理 Value 属性变更
double oldValue = winrt::unbox_value<double>(e.OldValue());
double newValue = winrt::unbox_value<double>(e.NewValue());
OutputDebugStringW((L"Value 从 " + winrt::to_hstring(oldValue) +
L" 变更为 " + winrt::to_hstring(newValue) + L"\n").c_str());
}
}
}
3. 依赖属性的值解析优先级
依赖属性系统按以下优先级解析属性值:
- 动画值(最高优先级)
- 本地值(通过 SetValue 设置)
- 模板绑定
- 样式 Setter
- 继承值
- 默认值(最低优先级)
cpp
// 演示属性值优先级
void DemonstrateDependencyPropertyPriority()
{
auto button = winrt::Microsoft::UI::Xaml::Controls::Button{};
// 1. 默认值(在注册时指定)
// button.FontSize() 返回默认值
// 2. 通过样式设置(优先级高于默认值)
auto style = winrt::Microsoft::UI::Xaml::Style{winrt::xaml_typename<winrt::Microsoft::UI::Xaml::Controls::Button>()};
auto setter = winrt::Microsoft::UI::Xaml::Setter{};
setter.Property(winrt::Microsoft::UI::Xaml::Controls::Control::FontSizeProperty());
setter.Value(winrt::box_value(16.0));
style.Setters().Append(setter);
button.Style(style);
// 3. 本地值(优先级最高,会覆盖样式值)
button.FontSize(20.0);
// 4. 清除本地值,恢复到样式值
button.ClearValue(winrt::Microsoft::UI::Xaml::Controls::Control::FontSizeProperty());
}
数据绑定底层原理
x:Bind 与 Binding 的区别
1. x:Bind(编译时绑定)
xml
<!-- x:Bind 在编译时生成代码 -->
<TextBlock Text="{x:Bind UserName, Mode=OneWay}"/>
<TextBlock Text="{x:Bind FormatAge(User.Age)}"/>
编译器生成的代码:
cpp
// MainWindow.g.h 中生成的绑定代码
class MainWindow_obj2_Bindings
{
private:
winrt::weak_ref<winrt::WinUI3App1C__::MainWindow> weakRefToRootObject;
public:
void Initialize(winrt::WinUI3App1C__::MainWindow const& rootObject)
{
weakRefToRootObject = winrt::make_weak(rootObject);
}
void Update()
{
if (auto rootObject = weakRefToRootObject.get())
{
// 获取绑定的值
hstring userName = rootObject.UserName();
hstring formattedAge = rootObject.FormatAge(rootObject.User().Age());
// 更新 UI 元素
rootObject.userNameTextBlock().Text(userName);
rootObject.ageTextBlock().Text(formattedAge);
}
}
};
x:Bind 的优势:
- 编译时检查:类型安全,编译时发现错误
- 高性能:直接调用,无反射开销
- 智能提示:IDE 支持自动完成
2. Binding(运行时绑定)
xml
<!-- Binding 使用反射,在运行时解析 -->
<TextBlock Text="{Binding UserName, Mode=OneWay}"/>
<TextBlock Text="{Binding User.Age, Converter={StaticResource AgeConverter}}"/>
cpp
// Binding 的内部实现原理(简化版)
class RuntimeBindingEngine
{
public:
static void EstablishBinding(
winrt::Microsoft::UI::Xaml::DependencyObject const& target,
winrt::Microsoft::UI::Xaml::DependencyProperty const& targetProperty,
winrt::Windows::Foundation::IInspectable const& source,
hstring const& path)
{
// 1. 解析属性路径
auto pathSegments = ParsePropertyPath(path);
// 2. 使用反射获取属性值
auto value = GetValueThroughReflection(source, pathSegments);
// 3. 应用转换器(如果有)
if (auto converter = GetConverter())
{
value = converter.Convert(value, /* ... */);
}
// 4. 设置目标属性
target.SetValue(targetProperty, value);
// 5. 建立变更通知
RegisterForPropertyChanges(source, path, [=](auto newValue)
{
// 属性变更时更新目标
target.SetValue(targetProperty, newValue);
});
}
private:
static std::vector<hstring> ParsePropertyPath(hstring const& path)
{
// 解析 "User.Age" 为 ["User", "Age"]
std::vector<hstring> segments;
// 实现路径解析逻辑...
return segments;
}
static winrt::Windows::Foundation::IInspectable GetValueThroughReflection(
winrt::Windows::Foundation::IInspectable const& source,
std::vector<hstring> const& pathSegments)
{
// 使用 WinRT 反射 API 获取属性值
auto currentObject = source;
for (auto&& segment : pathSegments)
{
// 获取属性值...
}
return currentObject;
}
};
双向绑定的实现
cpp
// 实现双向绑定的接口
namespace winrt::WinUI3App1C__::implementation
{
struct UserViewModel : UserViewModelT<UserViewModel>
{
private:
hstring m_userName;
int32_t m_age;
// 属性变更事件
winrt::event<winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;
public:
// 实现 INotifyPropertyChanged
winrt::event_token PropertyChanged(winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
return m_propertyChanged.add(handler);
}
void PropertyChanged(winrt::event_token const& token)
{
m_propertyChanged.remove(token);
}
// 带变更通知的属性
hstring UserName() const { return m_userName; }
void UserName(hstring const& value)
{
if (m_userName != value)
{
m_userName = value;
RaisePropertyChanged(L"UserName");
}
}
int32_t Age() const { return m_age; }
void Age(int32_t value)
{
if (m_age != value)
{
m_age = value;
RaisePropertyChanged(L"Age");
}
}
private:
void RaisePropertyChanged(hstring const& propertyName)
{
m_propertyChanged(*this, winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventArgs{propertyName});
}
};
}
在 XAML 中使用双向绑定:
xml
<!-- TwoWay 绑定会在控件值变化时更新源属性 -->
<TextBox Text="{x:Bind ViewModel.UserName, Mode=TwoWay}"/>
<Slider Value="{x:Bind ViewModel.Age, Mode=TwoWay}"/>
XAML 资源系统详解
资源查找机制
XAML 资源系统使用层次化查找:
xml
<!-- App.xaml - 应用程序级资源 -->
<Application.Resources>
<SolidColorBrush x:Key="AppPrimaryBrush" Color="Blue"/>
<Style x:Key="AppButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{StaticResource AppPrimaryBrush}"/>
</Style>
</Application.Resources>
xml
<!-- MainWindow.xaml - 窗口级资源 -->
<Window.Resources>
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="White"/>
<local:MyConverter x:Key="BoolToVisibilityConverter"/>
</Window.Resources>
<Grid>
<Grid.Resources>
<!-- 页面级资源 -->
<SolidColorBrush x:Key="GridBackgroundBrush" Color="LightGray"/>
</Grid.Resources>
<Button Background="{StaticResource AppPrimaryBrush}"
Style="{StaticResource AppButtonStyle}"/>
</Grid>
资源查找的 C++ 实现
cpp
// 资源查找的内部实现
class ResourceLookup
{
public:
static winrt::Windows::Foundation::IInspectable FindResource(
winrt::Microsoft::UI::Xaml::FrameworkElement const& element,
winrt::Windows::Foundation::IInspectable const& key)
{
// 1. 从当前元素开始查找
auto current = element;
while (current != nullptr)
{
if (current.Resources().HasKey(key))
{
return current.Resources().Lookup(key);
}
// 2. 向上查找父元素
current = current.Parent().try_as<winrt::Microsoft::UI::Xaml::FrameworkElement>();
}
// 3. 查找应用程序资源
auto app = winrt::Microsoft::UI::Xaml::Application::Current();
if (app.Resources().HasKey(key))
{
return app.Resources().Lookup(key);
}
// 4. 查找系统资源
return FindSystemResource(key);
}
private:
static winrt::Windows::Foundation::IInspectable FindSystemResource(
winrt::Windows::Foundation::IInspectable const& key)
{
// 查找系统定义的资源(如系统颜色、字体等)
return nullptr;
}
};
动态资源和主题切换
cpp
// 实现主题切换
class ThemeManager
{
private:
winrt::Microsoft::UI::Xaml::ResourceDictionary m_lightTheme;
winrt::Microsoft::UI::Xaml::ResourceDictionary m_darkTheme;
public:
void InitializeThemes()
{
// 创建浅色主题
m_lightTheme = winrt::Microsoft::UI::Xaml::ResourceDictionary{};
m_lightTheme.Insert(L"BackgroundBrush",
winrt::Microsoft::UI::Xaml::Media::SolidColorBrush{winrt::Windows::UI::Colors::White()});
m_lightTheme.Insert(L"ForegroundBrush",
winrt::Microsoft::UI::Xaml::Media::SolidColorBrush{winrt::Windows::UI::Colors::Black()});
// 创建深色主题
m_darkTheme = winrt::Microsoft::UI::Xaml::ResourceDictionary{};
m_darkTheme.Insert(L"BackgroundBrush",
winrt::Microsoft::UI::Xaml::Media::SolidColorBrush{winrt::Windows::UI::Colors::Black()});
m_darkTheme.Insert(L"ForegroundBrush",
winrt::Microsoft::UI::Xaml::Media::SolidColorBrush{winrt::Windows::UI::Colors::White()});
}
void ApplyTheme(bool isDarkTheme)
{
auto app = winrt::Microsoft::UI::Xaml::Application::Current();
auto mergedDictionaries = app.Resources().MergedDictionaries();
// 移除当前主题
mergedDictionaries.Clear();
// 应用新主题
if (isDarkTheme)
{
mergedDictionaries.Append(m_darkTheme);
}
else
{
mergedDictionaries.Append(m_lightTheme);
}
// 通知所有控件更新
InvalidateVisualTree();
}
private:
void InvalidateVisualTree()
{
// 遍历所有窗口和控件,触发重新绘制
// 这会导致所有 DynamicResource 引用重新解析
}
};
模板和样式机制
控件模板的内部工作原理
cpp
// 控件模板的应用过程
class TemplatedControl : public winrt::Microsoft::UI::Xaml::Controls::Control
{
protected:
virtual void OnApplyTemplate() override
{
// 1. 基类处理
__super::OnApplyTemplate();
// 2. 查找模板中的命名元素
auto contentPresenter = GetTemplateChild(L"PART_ContentPresenter")
.try_as<winrt::Microsoft::UI::Xaml::Controls::ContentPresenter>();
auto border = GetTemplateChild(L"PART_Border")
.try_as<winrt::Microsoft::UI::Xaml::Controls::Border>();
// 3. 建立模板绑定
if (contentPresenter)
{
// 绑定内容属性
auto binding = winrt::Microsoft::UI::Xaml::Data::Binding{};
binding.Source(*this);
binding.Path(winrt::Microsoft::UI::Xaml::PropertyPath{L"Content"});
winrt::Microsoft::UI::Xaml::Data::BindingOperations::SetBinding(
contentPresenter,
winrt::Microsoft::UI::Xaml::Controls::ContentPresenter::ContentProperty(),
binding);
}
// 4. 注册模板元素的事件
if (border)
{
border.PointerEntered([this](auto&&, auto&&) { OnPointerEntered(); });
border.PointerExited([this](auto&&, auto&&) { OnPointerExited(); });
}
}
private:
void OnPointerEntered()
{
// 处理鼠标进入
winrt::Microsoft::UI::Xaml::VisualStateManager::GoToState(*this, L"PointerOver", true);
}
void OnPointerExited()
{
// 处理鼠标离开
winrt::Microsoft::UI::Xaml::VisualStateManager::GoToState(*this, L"Normal", true);
}
};
自定义控件模板
xml
<!-- 定义自定义控件模板 -->
<Style x:Key="CustomButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="PART_Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="5">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="PART_Border.Background" Value="LightBlue"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Target="PART_Border.Background" Value="DarkBlue"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
自定义标记扩展
创建自定义标记扩展
cpp
// CustomExtension.idl
namespace WinUI3App1C__
{
[default_interface]
runtimeclass LocalizationExtension : Microsoft.UI.Xaml.Markup.MarkupExtension
{
LocalizationExtension();
LocalizationExtension(String key);
String Key;
String DefaultValue;
}
}
cpp
// LocalizationExtension.h
namespace winrt::WinUI3App1C__::implementation
{
struct LocalizationExtension : LocalizationExtensionT<LocalizationExtension>
{
private:
hstring m_key;
hstring m_defaultValue;
public:
LocalizationExtension() = default;
LocalizationExtension(hstring const& key) : m_key(key) {}
hstring Key() const { return m_key; }
void Key(hstring const& value) { m_key = value; }
hstring DefaultValue() const { return m_defaultValue; }
void DefaultValue(hstring const& value) { m_defaultValue = value; }
// 实现 MarkupExtension 的核心方法
winrt::Windows::Foundation::IInspectable ProvideValue(
winrt::Microsoft::UI::Xaml::Markup::IXamlServiceProvider const& serviceProvider) override;
};
}
cpp
// LocalizationExtension.cpp
winrt::Windows::Foundation::IInspectable LocalizationExtension::ProvideValue(
winrt::Microsoft::UI::Xaml::Markup::IXamlServiceProvider const& serviceProvider)
{
// 1. 获取资源加载器
auto resourceLoader = winrt::Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView();
// 2. 尝试加载本地化字符串
try
{
hstring localizedText = resourceLoader.GetString(m_key);
if (!localizedText.empty())
{
return winrt::box_value(localizedText);
}
}
catch (...)
{
// 资源不存在,使用默认值
}
// 3. 返回默认值或键名
hstring fallback = !m_defaultValue.empty() ? m_defaultValue : m_key;
return winrt::box_value(fallback);
}
在 XAML 中使用自定义标记扩展:
xml
<Window xmlns:local="using:WinUI3App1C__">
<TextBlock Text="{local:LocalizationExtension Key=WelcomeMessage, DefaultValue='Welcome!'}"/>
<Button Content="{local:LocalizationExtension ClickMe}"/>
</Window>
总结
本部分深入讲解了 XAML 框架的核心机制:
- XAML 编译:理解 XAML 如何转换为 C++ 代码
- 依赖属性:掌握 WinUI 3 属性系统的底层实现
- 数据绑定:了解编译时和运行时绑定的区别和原理
- 资源系统:掌握资源查找和主题切换机制
- 模板系统:理解控件模板的应用和自定义
- 标记扩展:学会创建自定义的 XAML 扩展
这些深层知识帮助我们更好地理解和使用 WinUI 3 框架。
这是 WinUI 3 WinRT C++ 完整教程的第五部分。下一部分我们将学习高级控件开发和性能优化技巧。