当前位置: 首页 > news >正文

C# Avalonia 19- DataBinding- BindToObjectDataProvider

自己写一个ObjectDataProvider类

ObjectDataProvider.cs代码

using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Xml.Linq;
using System.Xml.XPath;
using Avalonia.Platform;
using System.Diagnostics;
using System.Linq;namespace Shares.Avalonia
{public partial class ObjectDataProvider : ObservableObject{[ObservableProperty]private Type? objectType;[ObservableProperty]private string? methodName;[ObservableProperty]private string? source;[ObservableProperty]private string? xPath;[ObservableProperty]private object? data;private bool isRefreshing;public ObjectDataProvider(){PropertyChanged += (_, e) =>{if (e.PropertyName is nameof(ObjectType)or nameof(MethodName)or nameof(Source)or nameof(XPath)){Refresh();}};}public void Refresh(){if (isRefreshing)return;isRefreshing = true;try{if (ObjectType != null && !string.IsNullOrWhiteSpace(MethodName)){Data = CallObjectMethod();return;}if (!string.IsNullOrWhiteSpace(Source) && !string.IsNullOrWhiteSpace(XPath)){Data = LoadFromXml();return;}Data = null;}finally{isRefreshing = false;}}private object? CallObjectMethod(){try{var instance = CreateInstanceEvenWithoutDefaultCtor(ObjectType!);var method = ObjectType!.GetMethod(MethodName!);return method?.Invoke(instance, null);}catch (Exception ex){Debug.WriteLine($"[ObjectDataProvider] Method invoke error: {ex}");return null;}}private object? LoadFromXml(){try{var uri = new Uri(Source!, UriKind.RelativeOrAbsolute);using var stream = AssetLoader.Open(uri);var doc = XDocument.Load(stream);var nodes = doc.XPathSelectElements(XPath!);// 只在 ObjectType 为空时推断,且避免循环触发if (ObjectType == null){var nodeName = GetLastNodeNameFromXPath(XPath!);var inferred = FindTypeByName(nodeName);if (inferred != null && inferred != ObjectType)ObjectType = inferred;// 若仍然找不到类型 → 返回 XElement 列表if (ObjectType == null)return new List<XElement>(nodes);}var listType = typeof(List<>).MakeGenericType(ObjectType!);IList list = (IList)Activator.CreateInstance(listType)!;foreach (var node in nodes){var obj = CreateObjectFromXml(node);if (obj != null)list.Add(obj);}return list;}catch (Exception ex){Debug.WriteLine($"[ObjectDataProvider] XML load error: {ex}");return null;}}private object? CreateObjectFromXml(XElement node){try{var instance = CreateInstanceEvenWithoutDefaultCtor(ObjectType!);if (instance == null)return null;foreach (var prop in ObjectType!.GetProperties(BindingFlags.Public | BindingFlags.Instance)){// 先查找 Elementvar el = node.Element(prop.Name);string? xmlValue = el?.Value;// 查找 Attributeif (xmlValue == null){var attr = node.Attribute(prop.Name);xmlValue = attr?.Value;}if (xmlValue == null)continue;try{object? converted = ConvertXmlValue(xmlValue, prop.PropertyType);if (converted != null || prop.PropertyType.IsClass)prop.SetValue(instance, converted);}catch (Exception ex){Debug.WriteLine($"[ObjectDataProvider] Convert error on {prop.Name}: {ex}");}}return instance;}catch (Exception ex){Debug.WriteLine($"[ObjectDataProvider] Object create error: {ex}");return null;}}// 支持 Enum、Nullable<T>、基本类型private static object? ConvertXmlValue(string value, Type targetType){try{// Nullable<T>var underlying = Nullable.GetUnderlyingType(targetType);if (underlying != null)return Convert.ChangeType(value, underlying, CultureInfo.InvariantCulture);// Enumif (targetType.IsEnum)return Enum.Parse(targetType, value, ignoreCase: true);// 默认行为return Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture);}catch{return null;}}private static object? CreateInstanceEvenWithoutDefaultCtor(Type type){try{var defaultCtor = type.GetConstructor(Type.EmptyTypes);if (defaultCtor != null)return defaultCtor.Invoke(null);// 使用“参数最少构造器”var ctor = type.GetConstructors().OrderBy(c => c.GetParameters().Length).First();var parameters = ctor.GetParameters();var args = new object?[parameters.Length];for (int i = 0; i < parameters.Length; i++)args[i] = GetDefaultValue(parameters[i].ParameterType);return ctor.Invoke(args);}catch (Exception ex){Debug.WriteLine($"[ObjectDataProvider] Create instance error: {ex}");return null;}}private static object? GetDefaultValue(Type t){if (t.IsValueType)return Activator.CreateInstance(t);return null;}private static string GetLastNodeNameFromXPath(string xpath){var p = xpath.Trim().Split('/', StringSplitOptions.RemoveEmptyEntries);return p.Length > 0 ? p[^1] : "";}private static Type? FindTypeByName(string name){try{foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()){foreach (var t in asm.GetTypes()){if (t.Name.Equals(name, StringComparison.OrdinalIgnoreCase))return t;}}return null;}catch (Exception ex){Debug.WriteLine($"[ObjectDataProvider] Find type error: {ex}");return null;}}}
}

BindToObjectDataProvider.axaml代码

<Window xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Height="550" Width="400"x:Class="AvaloniaUI.BindToObjectDataProvider"xmlns:data="using:AvaloniaUI.Demos.Book._19.StoreDatabase"Title="BindToObjectDataProvider"><Window.Resources><!--<ObjectDataProvider x:Key="products"ObjectType="data:StoreDb1"MethodName="GetProducts"/>--><ObjectDataProvider x:Key="products"Source="avares://AvaloniaUI/Resources/Datas/store.xml"XPath="/NewDataSet/Products"ObjectType="data:Product"/>
</Window.Resources><Grid RowDefinitions="*,auto,*"><Grid RowDefinitions="auto,*"><TextBlock Margin="5">ObjectDataProvider Example...</TextBlock><ListBox Grid.Row="1"x:Name="lstProducts"Margin="5"ItemsSource="{Binding Source={StaticResource products}, Path=Data}"><ListBox.ItemTemplate><DataTemplate x:DataType="data:Product"><TextBlock Text="{Binding ModelName}" /></DataTemplate></ListBox.ItemTemplate></ListBox></Grid><GridSplitter Grid.Row="1"Height="5"HorizontalAlignment="Stretch"VerticalAlignment="Bottom"ResizeDirection="Rows"ResizeBehavior="PreviousAndNext" /><Border Grid.Row="2"Padding="7"Margin="7"Background="LightSteelBlue"><Grid DataContext="{Binding #lstProducts.SelectedItem}" x:DataType="data:Product"RowDefinitions="auto,auto,auto,auto,*"ColumnDefinitions="auto,*"><TextBlock Margin="7">Model Number:</TextBlock><TextBox Margin="5"Grid.Column="1"Text="{Binding ModelNumber}" /><TextBlock Margin="7"Grid.Row="1">Model Name:</TextBlock><TextBox Margin="5"Grid.Row="1"Grid.Column="1"Text="{Binding ModelName}" /><TextBlock Margin="7"Grid.Row="2">Unit Cost:</TextBlock><TextBox Margin="5"Grid.Row="2"Grid.Column="1"Text="{Binding UnitCost}" /><TextBlock Margin="7,7,7,0"Grid.Row="3">Description:</TextBlock><ScrollViewer Grid.Row="4"Grid.Column="0"Grid.ColumnSpan="2"><TextBox Margin="7"AcceptsReturn="True"TextWrapping="Wrap"Text="{Binding Description}" /></ScrollViewer></Grid></Border></Grid>
</Window>

BindToObjectDataProvider.axaml.cs代码

using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;namespace AvaloniaUI;public partial class BindToObjectDataProvider : Window
{public BindToObjectDataProvider(){InitializeComponent();}
}

运行效果

image

 

http://www.gsyq.cn/news/196715.html

相关文章:

  • 个人开发者买多少token合适?起步包满足日常测试需求
  • 按token收费合理吗?相比固定月费,按量付费更节省成本
  • Rockchip开发工具终极指南:简单三步完成快速安装配置
  • PythonWin7终极指南:在Windows 7上轻松安装Python 3.9+
  • CreamInstaller终极完整教程:新手快速掌握DLC解锁神器
  • Turing显卡ReBAR解锁终极指南:老旧主板性能突破实战
  • 如何用CosyVoice3实现多语言情感语音生成?支持中文方言与英文音素标注
  • CosyVoice3适合哪些应用场景?教育、娱乐、客服、影视全都能用
  • HTML页面嵌入CosyVoice3生成音频?前端展示语音成果的新方式
  • 微信小程序AR开发实战:从零打造沉浸式增强现实应用
  • zlib数据压缩库完全指南:从入门到精通
  • 视频稳定终极指南:陀螺仪防抖技术的完整解析
  • 实战指南:微服务架构的Kubernetes部署全流程解析
  • SoloPi 自动化测试工具:从入门到精通的完整实战指南
  • 4S店售后服务提醒:保养预约自动语音通知
  • Windows 7上安装Python 3.9+的完整解决方案
  • PoeCharm终极安装配置完整指南
  • PythonWin7完全指南:让Windows 7用户也能畅享最新Python版本
  • CosyVoice3支持盲文转换吗?暂无此功能
  • 2025年质量好的门座起重机/移动式港口起重机厂家最新热销排行 - 品牌宣传支持者
  • 特殊儿童教学支持:自闭症儿童偏好特定语音风格
  • 完整指南:如何使用pose-search实现实时人体动作识别与姿态分析
  • LCD基础原理入门必看:一文说清显示技术核心要点
  • 电子书转有声书神器:一键打造专属听觉图书馆
  • 个性化消息回复:朋友间发送定制语音气泡
  • 终极跨平台苹方字体解决方案:免费提升中文显示品质
  • CosyVoice3资源占用监控:GPU显存CPU内存实时查看
  • API调用频率限制:防止恶意刷量保护服务器稳定
  • 开源SDR接收器OpenWebRX:浏览器即可探索无线电世界
  • 超详细版Vivado下载流程(专为Artix-7设计)