XAML 深入学习 (三) 高级UI开发‌

一、架构与设计模式

MVVM深度解耦‌

数据驱动界面‌:XAML通过声明式绑定(如{Binding Path})自动同步业务逻辑与UI状态,无需手动更新控件

例子:

MainWindow.xaml



    
        
        
        
        
        
        
        
        
        
        

MainWindow.xaml.cs

using System.ComponentModel;
using System.Windows;

namespace DataBindingDemo {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
            DataContext = new EmployeeViewModel(); // 关键:设置数据上下文
        }
    }

    public class EmployeeViewModel : INotifyPropertyChanged {
        private string _employeeName = "张三";
        private double _salary = 8000;
        private bool _isManager;

        public string EmployeeName {
            get => _employeeName;
            set { _employeeName = value; OnPropertyChanged(); }
        }

        public double Salary {
            get => _salary;
            set { _salary = value; OnPropertyChanged(); }
        }

        public bool IsManager {
            get => _isManager;
            set { _isManager = value; OnPropertyChanged(); }
        }

        public RelayCommand SubmitCommand => new RelayCommand(_ => {
            MessageBox.Show($"已提交: {EmployeeName}, 薪资: {Salary:C2}, 经理: {IsManager}");
        });

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string name = null) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }

    public class RelayCommand : System.Windows.Input.ICommand {
        private readonly Action _execute;
        public RelayCommand(Action execute) => _execute = execute;
        public bool CanExecute(object parameter) => true;
        public void Execute(object parameter) => _execute(parameter);
        public event EventHandler CanExecuteChanged;
    }
}
 
  

命令模式集成‌:ICommand接口实现事件与逻辑分离(如异步操作封装至RelayCommand)

例子:

RelayCommandExample.xaml



    
        

MainWindow.xaml.cs

 System.Windows;
using System.Threading.Tasks;

namespace CommandDemo {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
            DataContext = new MainViewModel();
        }
    }

    public class MainViewModel {
        public ICommand LoadDataCommand => new RelayCommand(async _ => {
            Status = "加载中...";
            await Task.Delay(2000); // 模拟耗时操作
            Status = $"数据加载完成 {DateTime.Now:T}";
        });

        private string _status = "准备就绪";
        public string Status {
            get => _status;
            set { _status = value; OnPropertyChanged(); }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string name = null) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }

    public class RelayCommand : ICommand {
        private readonly Action _execute;
        public RelayCommand(Action execute) => _execute = execute;
        public bool CanExecute(object parameter) => true;
        public void Execute(object parameter) => _execute(parameter);
        public event EventHandler CanExecuteChanged;
    }
}
 
  

依赖注入支持‌:结合DI容器(如Microsoft.Extensions.DependencyInjection)管理ViewModel生命周期

例子:

App.xaml.cs


using Microsoft.Extensions.DependencyInjection;
using System.Windows;

public partial class App : Application
{
    public static IServiceProvider ServiceProvider { get; private set; }

    protected override void OnStartup(StartupEventArgs e)
    {
        var services = new ServiceCollection();
        services.AddTransient(); // 每次请求新建实例
        services.AddSingleton(); // 单例服务
        ServiceProvider = services.BuildServiceProvider();
        
        var mainWindow = new MainWindow();
        mainWindow.Show();
    }
}

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = App.ServiceProvider.GetRequiredService();
    }
}

 MainViewModel.cs

public class MainViewModel
{
    private readonly IDataService _dataService;
    
    public MainViewModel(IDataService dataService)
    {
        _dataService = dataService; // 通过构造函数注入
        LoadData();
    }

    private async void LoadData()
    {
        Data = await _dataService.GetDataAsync();
    }
}

动态UI架构‌

控件模板化‌:通过重写ControlTemplate实现Material Design等复杂视觉效果(如浮动阴影、动态色彩)

例子:

MaterialButton.xaml



    

MainWindow.xaml


    
        
    
    
    
        


数据模板动态生成‌:DataTemplateSelector根据数据类型实时切换控件样式

例子:

MainWindow.xaml



    
        
            
                
            
        
        
        
            
                
            
        
        
        
    
    
    

CustomTemplateSelector.cs

using System.Windows;
using System.Windows.Controls;

namespace TemplateSelectorDemo {
    public class CustomTemplateSelector : DataTemplateSelector {
        public DataTemplate TextTemplate { get; set; }
        public DataTemplate ImageTemplate { get; set; }
        
        public override DataTemplate SelectTemplate(object item, 
            DependencyObject container) {
            return item is TextItem ? TextTemplate : 
                   item is ImageItem ? ImageTemplate : null;
        }
    }
}

 ViewModels.cs

 TemplateSelectorDemo {
    public abstract class BaseItem {}
    
    public class TextItem : BaseItem {
        public string Content { get; set; } = "文本内容";
    }
    
    public class ImageItem : BaseItem {
        public string Path { get; set; } = "image.png";
    }
    
    public class MainViewModel {
        public ObservableCollection Items { get; } = new() {
            new TextItem(),
            new ImageItem(),
            new TextItem()
        };
    }
}


二、高级UI表现力

声明式动画引擎‌


    

XAML原生支持时间轴动画与关键帧控制

视觉层级管理‌

视觉树操作‌:VisualTreeHelper动态遍历/修改UI元素层级结构

例子:

VisualTreeHelperDemo.xaml



    
        

MainWindow.xaml.cs

 System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace VisualTreeDemo {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
            MainPanel.Children.Add(new TextBlock { Text = "原始元素1" });
            MainPanel.Children.Add(new TextBlock { Text = "原始元素2" });
        }

        private void FindChildren_Click(object sender, RoutedEventArgs e) {
            TreeViewer.Items.Clear();
            TraverseVisualTree(MainPanel, 0);
        }

        private void TraverseVisualTree(DependencyObject parent, int depth) {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) {
                var child = VisualTreeHelper.GetChild(parent, i);
                TreeViewer.Items.Add(new string(' ', depth*4) + child.GetType().Name);
                
                if (VisualTreeHelper.GetChildrenCount(child) > 0) {
                    TraverseVisualTree(child, depth + 1);
                }
            }
        }

        private void ModifyStyle_Click(object sender, RoutedEventArgs e) {
            ApplyStyleToTextBlocks(MainPanel);
        }

        private void ApplyStyleToTextBlocks(DependencyObject parent) {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) {
                var child = VisualTreeHelper.GetChild(parent, i);
                
                if (child is TextBlock tb) {
                    tb.Foreground = Brushes.Red;
                    tb.FontWeight = FontWeights.Bold;
                }
                ApplyStyleToTextBlocks(child);
            }
        }
    }
}

 混合渲染‌:集成Win2D或SkiaSharp实现GPU加速绘制(如复杂几何图形)

例子:

MainWindow.xaml



    
        
    

MainWindow.xaml.cs

using SkiaSharp;
using System.Windows;

namespace SkiaSharpDemo {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }

        private void OnPaintSurface(object sender, 
            SKPaintSurfaceEventArgs e) {
            var surface = e.Surface;
            var canvas = surface.Canvas;
            
            // 清空画布
            canvas.Clear(SKColors.White);
            
            // 创建渐变画笔
            using var paint = new SKPaint {
                Shader = SKShader.CreateLinearGradient(
                    new SKPoint(0, 0),
                    new SKPoint(e.Info.Width, e.Info.Height),
                    new[] { SKColors.Blue, SKColors.Red },
                    new[] { 0f, 1f },
                    SKShaderTileMode.Clamp)
            };
            
            // 绘制复杂路径
            using var path = new SKPath();
            path.MoveTo(100, 100);
            path.CubicTo(300, 50, 200, 200, 400, 150);
            path.LineTo(400, 300);
            path.ArcTo(200, 200, 0, SKPathArcSize.Large, 
                      SKPathDirection.CounterClockwise, 100, 300);
            path.Close();
            
            canvas.DrawPath(path, paint);
        }
    }
}

 App.xaml



主题与样式系统‌

全局资源字典‌:ResourceDictionary统一管理颜色、字体等设计资产,支持运行时动态切换

例子:

App.xaml



    
        
            
                
            
        
    

Themes/LightTheme.xaml


    #FF42A5F5
    
    Segoe UI
    10

 Themes/DarkTheme.xaml


    #FF1565C0
    
    Consolas
    10

MainWindow.xaml


    
        

MainWindow.xaml.cs

using System.Windows;
using System.Windows.Media;

namespace ResourceDemo {
    public partial class MainWindow : Window {
        public MainWindow() => InitializeComponent();

        private void ChangeTheme(string themePath) {
            var dict = new ResourceDictionary { Source = new Uri(themePath, UriKind.Relative) };
            Application.Current.Resources.MergedDictionaries[0] = dict;
        }

        private void DarkTheme_Click(object sender, RoutedEventArgs e) 
            => ChangeTheme("Themes/DarkTheme.xaml");

        private void LightTheme_Click(object sender, RoutedEventArgs e) 
            => ChangeTheme("Themes/LightTheme.xaml");
    }
}

 状态样式触发器‌:VisualStateManager根据控件状态(如Pressed、Disabled)自动切换样式

例子:

MainWindow.xaml



    
        
    

MainWindow.xaml.cs

using System.Windows;

namespace VisualStateDemo {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }
    }
}

 三、跨平台能力革新

单一代码库多端部署‌

.NET MAUI机制‌:XAML布局自适应不同平台(iOS/Android/Windows),共享核心业务逻辑

例子:

MainPage.xaml




    
        
            
            
            
            

MainPage.xaml.cs

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace MauiDemo;

public partial class MainPage : ContentPage, INotifyPropertyChanged
{
    private int _count = 0;
    private string _counterText = "Click count: 0";
    
    public string CounterText {
        get => _counterText;
        set {
            _counterText = value;
            OnPropertyChanged();
        }
    }
    
    public Command CounterCommand { get; }
    
    public MainPage()
    {
        InitializeComponent();
        CounterCommand = new Command(OnCounterClicked);
        BindingContext = this;
    }
    
    private void OnCounterClicked()
    {
        _count++;
        CounterText = $"Click count: {_count}";
        
        SemanticScreenReader.Announce(CounterText);
    }
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected void OnPropertyChanged([CallerMemberName] string name = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

Platforms/Android/Resources/values/styles.xml


    

Platforms/iOS/Resources/SecondaryB

using Microsoft.Maui.Controls.PlatformConfiguration;
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;

namespace MauiDemo;

public static class SecondaryButtonStyle
{
    public static Button ApplySecondaryStyle(this Button button)
    {
        button.BackgroundColor = Colors.White;
        button.TextColor = Colors.Black;
        button.On().SetUseSafeArea(true);
        return button;
    }
}


响应式布局‌:FlexLayout与Grid结合自适应规则应对屏幕尺寸变化

例子:

ResponsivePage.xaml




    
        
        
        

ResponsivePage.xaml.cs

using Microsoft.Maui.Controls;

namespace ResponsiveDemo;

public partial class ResponsivePage : ContentPage
{
    public ResponsivePage()
    {
        InitializeComponent();
        
        // 监听尺寸变化
        this.SizeChanged += (s,e) => {
            bool isWide = this.Width > 600;
            VisualStateManager.GoToState(
                this, 
                isWide ? "WideLayout" : "NarrowLayout"
            );
        };
    }
}

 App.xaml



    
        
            
            
            
                
                    
                        
                    
                
                
                    
                        
                    
                
            
        
    

原生性能优化‌

渲染器定制‌:通过Handler机制重写平台原生控件行为(如Android下定制按钮阴影)

例子:

CustomButton.xaml




    

CustomButton.xaml.cs

using Microsoft.Maui.Controls;

namespace CustomRendererDemo;

public partial class CustomButton : ContentView
{
    public CustomButton()
    {
        InitializeComponent();
    }
}

CustomButtonHandler.cs

using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;

namespace CustomRendererDemo;

public partial class CustomButtonHandler : ViewHandler
{
    protected override Android.Widget.Button CreatePlatformView()
    {
        var button = new Android.Widget.Button(Context);
        return button;
    }

    protected override void ConnectHandler(Android.Widget.Button platformView)
    {
        base.ConnectHandler(platformView);
        UpdateShadow();
    }

    void UpdateShadow()
    {
        if (PlatformView == null) return;
        
        PlatformView.SetShadowLayer(
            radius: 10f, 
            dx: 5f, 
            dy: 5f, 
            color: Android.Graphics.Color.Argb(100, 0, 0, 0));
    }
}

MauiProgram.cs

using Microsoft.Maui;
using Microsoft.Maui.Hosting;

namespace CustomRendererDemo;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp()
            .ConfigureMauiHandlers(handlers => {
                handlers.AddHandler();
            });

        return builder.Build();
    }
}


渲染管线接入‌:Avalonia框架支持Skia自定义绘制管线实现高性能渲染

例子:

CustomSkiaControl.cs


using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Skia;
using SkiaSharp;

public class CustomSkiaControl : Control
{
    protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
    {
        base.OnAttachedToVisualTree(e);
        InvalidateVisual();
    }

    public override void Render(DrawingContext context)
    {
        var skiaContext = context.GetFeature();
        using (var lease = skiaContext.Lease())
        {
            var canvas = lease.SkCanvas;
            canvas.Clear(SKColors.White);
            
            // 绘制渐变背景
            using (var paint = new SKPaint())
            {
                var rect = new SKRect(0, 0, (float)Bounds.Width, (float)Bounds.Height);
                paint.Shader = SKShader.CreateLinearGradient(
                    new SKPoint(0, 0),
                    new SKPoint((float)Bounds.Width, (float)Bounds.Height),
                    new[] { SKColors.Blue, SKColors.Green },
                    new[] { 0f, 1f },
                    SKShaderTileMode.Clamp);
                canvas.DrawRect(rect, paint);
            }

            // 绘制文本
            using (var paint = new SKPaint())
            {
                paint.Color = SKColors.Red;
                paint.TextSize = 24;
                paint.IsAntialias = true;
                canvas.DrawText("SkiaSharp Rendering", 20, 40, paint);
            }
        }
    }
}

MainWindow.xaml


    


四、性能与可维护性

渲染优化技术‌

UI虚拟化‌:VirtualizingStackPanel应对万级数据列表,仅渲染可视区域元素

例子:

MainWindow.xaml



    
        
            
                
            
        
    

MainWindow.xaml.cs

using System.Collections.ObjectModel;
using System.Windows;

namespace VirtualizationDemo
{
    public partial class MainWindow : Window
    {
        public ObservableCollection Items { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            Items = new ObservableCollection();
            
            // 生成10万条测试数据
            for (int i = 0; i < 100000; i++)
            {
                Items.Add(new DataItem { Name = $"项目 {i + 1}" });
            }
            
            DataContext = this;
        }
    }

    public class DataItem
    {
        public string Name { get; set; }
    }
}

 异步加载策略‌:PriorityBinding优先显示关键数据,后台加载次要内容

例子:

MainWindow.xaml



    
        
        
            
                
                    
                    
                
            
        
        
        
        
            
                
                    
                    
                
            
        
    

MainWindow.xaml.cs

using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows;

namespace PriorityBindingDemo
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private string _loadingText = "加载中...";
        public string LoadingText {
            get => _loadingText;
            set => SetField(ref _loadingText, value);
        }

        private string _basicInfo;
        public string BasicInfo {
            get => _basicInfo ?? LoadBasicInfo();
            set => SetField(ref _basicInfo, value);
        }

        private string _fullDescription;
        public string FullDescription {
            get => _fullDescription ?? Task.Run(LoadFullDescription).Result;
            set => SetField(ref _fullDescription, value);
        }

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }

        private string LoadBasicInfo() {
            // 模拟快速加载的关键数据
            Task.Delay(300).Wait();
            return "商品名称:智能手机(基础信息已加载)";
        }

        private async Task LoadFullDescription() {
            // 模拟耗时的详细数据加载
            await Task.Delay(3000);
            return "产品详情:\n- 6.5英寸AMOLED屏幕\n- 骁龙888处理器\n- 5000mAh电池\n(完整描述已加载)";
        }

        // INotifyPropertyChanged实现
        public event PropertyChangedEventHandler PropertyChanged;
        protected void SetField(ref T field, T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = null) {
            field = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

 开发效率工具链‌

实时热重载‌:修改XAML即时预览效果(注:需规避XamlC编译冲突)
Live Visual Tree调试‌:运行时动态检查/修改XAML属性

你可能感兴趣的:(C#,学习,ui,xml,xhtml,c#)