You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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集合的变更事件

  1. 在ViewModel中定义带变更通知的集合:
public ObservableCollection<double> MarkerValues { get; } = new ObservableCollection<double>();
  1. 在页面代码后台绑定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封装逻辑:

  1. 创建自定义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 });
        }
    }
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 16:14:50