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

Xamarin.Forms:通过数据绑定绘制指定布局参数的矩形

MVVM模式下实现嵌套矩形的绑定绘制方案

要解决你遇到的问题——在外部矩形内通过MVVM数据绑定绘制动态子矩形,不用Code Behind硬编码界面,推荐用自定义绑定容器View的方案,完美避开AbsoluteLayout和CollectionView的嵌套限制,同时保持MVVM的解耦性。

1. 定义子矩形的数据模型

在ViewModel层创建RectItem类,包含所有需要绑定的属性,实现INotifyPropertyChanged支持属性变更通知:

public class RectItem : INotifyPropertyChanged
{
    private double _x;
    public double X
    {
        get => _x;
        set { _x = value; OnPropertyChanged(); }
    }

    private double _y;
    public double Y
    {
        get => _y;
        set { _y = value; OnPropertyChanged(); }
    }

    private double _width;
    public double Width
    {
        get => _width;
        set { _width = value; OnPropertyChanged(); }
    }

    private double _height;
    public double Height
    {
        get => _height;
        set { _height = value; OnPropertyChanged(); }
    }

    private Color _backgroundColor;
    public Color BackgroundColor
    {
        get => _backgroundColor;
        set { _backgroundColor = value; OnPropertyChanged(); }
    }

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

2. 在ViewModel中维护子矩形集合

创建主ViewModel,用ObservableCollection<RectItem>存储子矩形数据,集合增删会自动通知View更新:

public class MainViewModel : INotifyPropertyChanged
{
    private ObservableCollection<RectItem> _rectItems;
    public ObservableCollection<RectItem> RectItems
    {
        get => _rectItems;
        set { _rectItems = value; OnPropertyChanged(); }
    }

    public MainViewModel()
    {
        // 可替换为业务逻辑获取的真实数据
        RectItems = new ObservableCollection<RectItem>
        {
            new RectItem { X = 20, Y = 20, Width = 100, Height = 80, BackgroundColor = Colors.LightBlue },
            new RectItem { X = 150, Y = 50, Width = 80, Height = 120, BackgroundColor = Colors.LightGreen },
            new RectItem { X = 80, Y = 130, Width = 120, Height = 70, BackgroundColor = Colors.LightSalmon }
        };
    }

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

3. 自定义容器View处理布局逻辑

继承AbsoluteLayout做自定义View,添加可绑定属性RectItems,集合变化时自动创建/移除子视图,同时监听单个矩形属性变更更新布局:

public class RectContainerView : AbsoluteLayout
{
    public static readonly BindableProperty RectItemsProperty =
        BindableProperty.Create(nameof(RectItems), typeof(ObservableCollection<RectItem>), typeof(RectContainerView), null, propertyChanged: OnRectItemsChanged);

    public ObservableCollection<RectItem> RectItems
    {
        get => (ObservableCollection<RectItem>)GetValue(RectItemsProperty);
        set => SetValue(RectItemsProperty, value);
    }

    private static void OnRectItemsChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var container = (RectContainerView)bindable;
        var oldCollection = oldValue as ObservableCollection<RectItem>;
        var newCollection = newValue as ObservableCollection<RectItem>;

        // 清理旧数据和监听
        if (oldCollection != null)
        {
            oldCollection.CollectionChanged -= container.OnCollectionChanged;
            container.ClearChildren();
        }

        // 绑定新集合并初始化视图
        if (newCollection != null)
        {
            newCollection.CollectionChanged += container.OnCollectionChanged;
            container.AddAllRects(newCollection);
        }
    }

    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                foreach (RectItem item in e.NewItems) AddSingleRect(item);
                break;
            case NotifyCollectionChangedAction.Remove:
                foreach (RectItem item in e.OldItems) RemoveSingleRect(item);
                break;
            case NotifyCollectionChangedAction.Reset:
                ClearChildren();
                break;
        }
    }

    private void AddAllRects(IEnumerable<RectItem> items)
    {
        foreach (var item in items) AddSingleRect(item);
    }

    private void AddSingleRect(RectItem item)
    {
        var boxView = new BoxView { BindingContext = item };
        // 绑定背景色
        boxView.SetBinding(BoxView.BackgroundColorProperty, nameof(RectItem.BackgroundColor));
        // 设置初始布局
        SetLayoutBounds(boxView, new Rect(item.X, item.Y, item.Width, item.Height));
        SetLayoutFlags(boxView, AbsoluteLayoutFlags.None);

        // 监听属性变化,实时更新布局
        item.PropertyChanged += (s, e) =>
        {
            if (e.PropertyName is nameof(RectItem.X) or nameof(RectItem.Y) or nameof(RectItem.Width) or nameof(RectItem.Height))
            {
                SetLayoutBounds(boxView, new Rect(item.X, item.Y, item.Width, item.Height));
            }
        };

        Children.Add(boxView);
    }

    private void RemoveSingleRect(RectItem item)
    {
        var target = Children.FirstOrDefault(v => v.BindingContext == item);
        if (target != null) Children.Remove(target);
    }
}

4. 在XAML中绑定使用

把自定义容器放到外部矩形(比如Frame)里,直接绑定ViewModel的RectItems集合:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourAppNamespace"
             x:Class="YourAppNamespace.MainPage">
    <ContentPage.BindingContext>
        <local:MainViewModel />
    </ContentPage.BindingContext>

    <!-- 外部矩形容器 -->
    <Frame BorderColor="#000" Padding="0" Margin="20" HeightRequest="300" WidthRequest="300">
        <local:RectContainerView RectItems="{Binding RectItems}" />
    </Frame>
</ContentPage>

方案亮点

  • 完全贴合MVVM模式,View仅负责展示,所有数据和逻辑集中在ViewModel
  • 支持子矩形动态增删,以及单个矩形坐标、尺寸、颜色的实时更新
  • 自定义View封装所有布局逻辑,复用性强,无需在Code Behind中操作界面元素

内容的提问来源于stack exchange,提问作者Bernd Morgeneyer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 17:55:04