如何在DevExpress RadialGauge中遍历集合生成标记及传递ViewModel数据?
问题描述
我有如下自定义控件:
<dxga:RadialGauge WidthRequest="350" HeightRequest="220"> <dxga:RadialScale StartAngle="180" StartValue="0" EndValue="{Binding ScaleSettings.ScaleEndValue}" ShowTickmarkLabels="True" MajorTickmarkCount="5" MinorTickmarkCount="4" SweepAngle="180" Fill="Transparent" TickmarkLabelPosition="Inside"> <dxga:RangeIndicator StartValue="0" EndValue="{Binding ScaleSettings.ScaleFirstStep}" StrokeCap="Square" StartThickness="20" Fill="#EEEEEE" /> [ ... ] </dxga:RadialScale> </dxga:RadialGauge>
我希望在上述代码的[ ... ]位置,通过子控件<dxga:MarkerIndicator Value="{Binding .}"/>遍历ObservableCollection,请问是否可行?
更新
我可以通过后台代码添加所需的指针/标记:
<dxga:RadialScale x:Name="scale"></dxga:RadialScale>
以及
scale.Indicators.Add(new MarkerIndicator() { Value = 50 });
但我的数据存储在ViewModel中,请问将ViewModel中的数据传递到后台代码的最佳方式是什么?
解决方案
问题1:能否在XAML中直接遍历ObservableCollection生成MarkerIndicator?
直接在XAML里用<dxga:MarkerIndicator>遍历ObservableCollection不可行,因为DevExpress的RadialScale的Indicators集合没有内置的ItemsSource绑定属性,无法像ListBox那样自动通过集合生成子控件实例。
问题2:从ViewModel传递数据到后台代码添加指示器的最佳方式
推荐以下几种实用方案:
方案1:监听ViewModel集合的变更事件
- 在ViewModel中定义带变更通知的集合:
public ObservableCollection<double> MarkerValues { get; } = new ObservableCollection<double>();
- 在页面代码后台绑定ViewModel后,监听集合的
CollectionChanged事件,同步更新指示器:
protected override void OnBindingContextChanged() { base.OnBindingContextChanged(); if (BindingContext is YourViewModel vm) { vm.MarkerValues.CollectionChanged += MarkerValues_CollectionChanged; // 初始化已存在的数据 foreach (var value in vm.MarkerValues) { scale.Indicators.Add(new MarkerIndicator { Value = value }); } } } private void MarkerValues_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) { foreach (var item in e.NewItems) { if (item is double val) scale.Indicators.Add(new MarkerIndicator { Value = val }); } } // 可选:处理移除、重置操作 else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove) { // 需要额外跟踪Indicator与数据的关联关系,再移除对应实例 } else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset) { scale.Indicators.Clear(); } }
这种方式能自动响应ViewModel中集合的增删操作,保持UI与数据同步。
方案2:用Behavior封装MVVM逻辑(更优雅)
如果想避免后台代码直接操作UI控件,可以自定义Behavior封装逻辑:
- 创建自定义Behavior:
public class RadialScaleMarkerBehavior : Behavior<RadialScale> { public static readonly BindableProperty MarkerValuesProperty = BindableProperty.Create(nameof(MarkerValues), typeof(ObservableCollection<double>), typeof(RadialScaleMarkerBehavior), null, propertyChanged: OnMarkerValuesChanged); public ObservableCollection<double> MarkerValues { get => (ObservableCollection<double>)GetValue(MarkerValuesProperty); set => SetValue(MarkerValuesProperty, value); } private static void OnMarkerValuesChanged(BindableObject bindable, object oldValue, object newValue) { var behavior = (RadialScaleMarkerBehavior)bindable; if (oldValue is ObservableCollection<double> oldCol) oldCol.CollectionChanged -= behavior.MarkerValues_CollectionChanged; if (newValue is ObservableCollection<double> newCol) { newCol.CollectionChanged += behavior.MarkerValues_CollectionChanged; behavior.UpdateMarkers(newCol); } } private void MarkerValues_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { if (sender is ObservableCollection<double> col) UpdateMarkers(col); } private void UpdateMarkers(ObservableCollection<double> values) { AssociatedObject.Indicators.Clear(); foreach (var val in values) { AssociatedObject.Indicators.Add(new MarkerIndicator { Value = val }); } } }
- 在XAML中引用Behavior:
<dxga:RadialScale StartAngle="180" ...> <dxga:RadialScale.Behaviors> <local:RadialScaleMarkerBehavior MarkerValues="{Binding MarkerValues}" /> </dxga:RadialScale.Behaviors> <!-- 其他指示器或RangeIndicator --> </dxga:RadialScale>
这种方式完全遵循MVVM模式,逻辑封装在Behavior中,复用性更强,后台无需直接操作UI控件。
方案3:页面加载时一次性同步数据
如果集合数据很少变更,可在页面加载时一次性读取ViewModel数据并添加指示器:
protected override void OnAppearing() { base.OnAppearing(); if (BindingContext is YourViewModel vm) { scale.Indicators.Clear(); foreach (var value in vm.MarkerValues) { scale.Indicators.Add(new MarkerIndicator { Value = value }); } } }
这种方式实现最简单,适合静态或低频变更的数据场景。
内容的提问来源于stack exchange,提问作者Kasper Sommer
相关产品推荐
相关产品推荐

