.NET MAUI中DataGridGrid的Renderer转Handler显示异常问题
问题描述
我正在将.NET MAUI中用作自定义ListView表头的DataGridGrid控件的Renderer转换为Handler。以下是自定义控件及其Android平台Renderer的代码(该控件是带有列的常规Grid控件):
自定义控件代码
namespace Test.Helpers.DataGrid.Helpers { public class DataGridGrid: Grid { public Action<bool>? OnResizeToggled; public Action<float>? OnResizeCommit { get; set; } public Action<float, bool>? OnResizing { get; set; } public Action OnSorting { get; set; } public int GridIndex { get; set; } } }
原Android Renderer代码
[assembly: ExportRenderer(typeof(DataGridGrid), typeof(DataGridGridRenderer))] namespace Test.Droid.Helpers { public class DataGridGridRenderer : ViewRenderer<DataGridGrid, View> { private bool _resizing; private float _initialX; private bool _handlerAttached; private DataGridGrid _prev; public DataGridGridRenderer(Context context) : base(context) { } public float ConvertPixelsToDp(float px) { var density = Context.Resources.DisplayMetrics.Density; return px / density; } protected override void OnElementChanged(ElementChangedEventArgs<DataGridGrid> e) { base.OnElementChanged(e); if (e.NewElement == null) return; if (_handlerAttached) return; _handlerAttached = true; Touch += HandleTouches; } private void HandleTouches(object sender, TouchEventArgs args) { // 触摸处理逻辑 } } }
当前MAUI Handler代码
namespace Test.Platforms.Android.Handlers { public partial class DataGridGridHandler : ViewHandler<DataGridGrid, View> { private bool _resizing; private float _initialX; private bool _handlerAttached; private DataGridGrid _prev; public DataGridGridHandler() : base(DGListViewMapper) { } public DataGridGridHandler(IPropertyMapper mapper, CommandMapper? commandMapper = null) : base(mapper, commandMapper) { } public static PropertyMapper<DataGridGrid, DataGridGridHandler> DGListViewMapper = new(ViewHandler.ViewMapper) { }; public float ConvertPixelsToDp(float px) { var density = Context.Resources.DisplayMetrics.Density; return px / density; } protected override View CreatePlatformView() { return new View(Context);// 返回空白视图 } } }
Handler注册代码(MAUIProgram.cs)
handlers.AddHandler(typeof(DataGridGrid), typeof(DataGridGridHandler));
当前Handler返回空白输出,无法正常显示带列名的网格表头。已知问题源于实例化了新的空白View,想了解如何仅绑定事件并复用原虚拟视图?
解决方案
核心问题在于你的DataGridGrid继承自MAUI的Grid控件,而当前Handler手动创建了一个空白的Android View,完全忽略了MAUI Grid本身的原生渲染逻辑,导致表头的列布局无法被正确渲染。正确的做法是复用MAUI Grid对应的Android原生实现,并仅添加触摸事件绑定逻辑:
修正后的Handler代码
namespace Test.Platforms.Android.Handlers { public partial class DataGridGridHandler : ViewHandler<DataGridGrid, MauiGrid> { private bool _resizing; private float _initialX; private bool _handlerAttached; // 复用MAUI Grid的PropertyMapper,保留Grid原有渲染逻辑 public static PropertyMapper<DataGridGrid, DataGridGridHandler> DGListViewMapper = new(GridHandler.Mapper) { // 如果需要针对DataGridGrid的自定义属性添加映射,在这里补充 }; public DataGridGridHandler() : base(DGListViewMapper) { } public DataGridGridHandler(IPropertyMapper mapper, CommandMapper? commandMapper = null) : base(mapper, commandMapper) { } public float ConvertPixelsToDp(float px) { var density = Context.Resources.DisplayMetrics.Density; return px / density; } // 创建MAUI Grid对应的Android原生视图MauiGrid protected override MauiGrid CreatePlatformView() { return new MauiGrid(Context); } protected override void OnElementChanged(ElementChangedEventArgs<DataGridGrid> e) { base.OnElementChanged(e); if (e.OldElement != null) { // 移除旧元素的触摸事件,防止内存泄漏 if (PlatformView != null) { PlatformView.Touch -= HandleTouches; _handlerAttached = false; } } if (e.NewElement != null && !_handlerAttached) { // 给新的原生视图绑定触摸事件 PlatformView.Touch += HandleTouches; _handlerAttached = true; } } protected override void DisconnectHandler(MauiGrid platformView) { // 销毁时移除事件绑定 platformView.Touch -= HandleTouches; _handlerAttached = false; base.DisconnectHandler(platformView); } private void HandleTouches(object sender, TouchEventArgs args) { // 保留原Renderer中的触摸处理逻辑 // 例如: // var motionEvent = args.Event; // switch (motionEvent.Action) // { // case MotionEventActions.Down: // _initialX = motionEvent.RawX; // _resizing = true; // args.Handled = false; // break; // // 其他触摸逻辑... // } } } }
关键修改点说明
- 泛型参数调整:将
ViewHandler<DataGridGrid, View>改为ViewHandler<DataGridGrid, MauiGrid>,MauiGrid是MAUI Grid控件在Android平台对应的原生实现类,确保Grid的列布局能被正常渲染。 - 复用Grid的PropertyMapper:使用
GridHandler.Mapper作为基础创建自定义Mapper,保留MAUI Grid原有的所有渲染逻辑,无需从零实现。 - 正确创建原生视图:
CreatePlatformView返回MauiGrid而非空白View,让MAUI能够正常渲染Grid的内容。 - 事件绑定与清理:在
OnElementChanged中为新元素绑定触摸事件,同时为旧元素移除事件;在DisconnectHandler中销毁事件绑定,避免内存泄漏。
这样修改后,Handler会复用MAUI Grid的原生渲染逻辑,同时添加你需要的触摸事件处理,表头就能正常显示列名,并且保留原有的调整大小、排序等交互逻辑。
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

