如何在XAML中填充ReadOnlyObservableCollection及定义含该属性的VM设计数据
我来帮你理清这两个关于ReadOnlyObservableCollection在XAML里的问题,都是实际开发中常见的场景:
首先要搞清楚:ReadOnlyObservableCollection<T>本质是个只读包装器——它套了一层普通的ObservableCollection<T>,对外只暴露只读接口(没有Add/Remove这类修改方法)。所以你没法直接在XAML里往它里面塞元素,因为XAML试图给集合添加内容时,本质是调用集合的Add方法,但这个类型根本没公开修改入口。
靠谱的做法是在你的视图模型内部维护一个可修改的ObservableCollection<T>实例,用它来初始化ReadOnlyObservableCollection<T>属性。比如:
public class ProcedureEditorViewModel { private readonly ObservableCollection<ProcedureViewModel> _procedures; public ReadOnlyObservableCollection<ProcedureViewModel> Procedures { get; } public ProcedureEditorViewModel() { _procedures = new ObservableCollection<ProcedureViewModel>(); Procedures = new ReadOnlyObservableCollection<ProcedureViewModel>(_procedures); // 运行时要加数据的话,直接操作_procedures就行 // _procedures.Add(new ProcedureViewModel { Name = "Procedure A" }); } }
如果是想在设计时通过XAML预览数据,那得靠视图模型内部的可修改集合来填充,而不是直接碰只读的那个属性。
你尝试的那种直接在XAML里给<viewModels:ProcedureEditorViewModel.Procedures>加子元素的方式肯定行不通——因为ReadOnlyObservableCollection没有公开的Add方法,XAML解析器会直接报错。
不过你完全可以在XAML里把这个视图模型设为设计数据,只是得换个方式填充集合,这里有两个常用方案:
- 方案一:在视图模型构造函数里加设计时专属逻辑
你可以在构造函数里判断当前是否处于设计模式,如果是,就往内部的可修改集合里塞测试数据:
using System.ComponentModel; using System.Windows; public class ProcedureEditorViewModel { private readonly ObservableCollection<ProcedureViewModel> _procedures; public ReadOnlyObservableCollection<ProcedureViewModel> Procedures { get; } public ProcedureEditorViewModel() { _procedures = new ObservableCollection<ProcedureViewModel>(); Procedures = new ReadOnlyObservableCollection<ProcedureViewModel>(_procedures); // 只在设计时填充测试数据 if (DesignerProperties.GetIsInDesignMode(new DependencyObject())) { _procedures.Add(new ProcedureViewModel { Name = "Procedure A" }); _procedures.Add(new ProcedureViewModel { Name = "Procedure B" }); } } }
然后在XAML里直接把视图模型设为设计时数据上下文就行:
<UserControl ... d:DataContext="{d:DesignInstance Type=viewModels:ProcedureEditorViewModel, IsDesignTimeCreatable=True}"> <!-- 你的界面元素 --> </UserControl>
- 方案二:用设计时资源集合(相对麻烦,不推荐)
要是不想在代码里写设计时逻辑,也可以在XAML里定义一个设计时的ObservableCollection资源,然后在视图模型的设计时构造函数里把这个集合的元素复制到内部的_procedures里。不过这种方式需要视图模型能访问到XAML资源,步骤多,一般还是第一种方案更省心。
总结一下:ReadOnlyObservableCollection本身不能被XAML直接修改,但你可以通过视图模型内部的可修改集合来填充数据——不管是运行时还是设计时场景都适用。
内容的提问来源于stack exchange,提问作者Haukinger

