我正在从事 WPF 应用程序开发。我们的对话框之一有一个 DataGrid。此 DataGrid 应显示有关某些 3D 点的信息。对于这一点,我们有一个 PointViewModel 类,它具有 4 个必需的主要属性 - Name、X、Y、Z:
public class PointViewModel : ViewModelBase
{
public string Name
{
get => _name;
set
{
_name = value;
NotifyPropertyChanged(nameof(Name));
}
}
public double X
{
get => _x;
set
{
_x = value;
NotifyPropertyChanged(nameof(X));
}
}
public double Y
{
get => _y;
set
{
_y = value;
NotifyPropertyChanged(nameof(Y));
}
}
public double Z
{
get => _z;
set
{
_z = value;
NotifyPropertyChanged(nameof(Z));
}
}
public ObservableCollection<PointCustomPropViewModel> CustomProperties => _customProperties;
public PointViewModel(string name, double x, double y, double z)
{
// in the real code this collection is empty at the beginning, but for the test I added 2 custom properties where I just "know" their names and values.
_customProperties = new ObservableCollection<PointCustomPropViewModel>()
{
new PointCustomPropViewModel("Test Prop 1", "Hello"),
new PointCustomPropViewModel("Test Prop 2", "World"),
};
Name = name;
X = x;
Y = y;
Z = z;
}
private readonly ObservableCollection<PointCustomPropViewModel> _customProperties;
private string _name;
private double _x;
private double _y;
private double _z;
}
每个点还可以有一些自定义属性。当应用程序刚启动时,我们不知道有关这些属性的任何信息,因此应该动态创建它们。对于这些自定义属性,每个点都有一个 CustomProperties 集合。每个 PointCustomPropViewModel 都有有关属性名称和属性值的信息,仅此而已:
public class PointCustomPropViewModel : ViewModelBase
{
public string PropName
{
get => _propName;
set
{
_propName = value;
NotifyPropertyChanged(nameof(PropName));
}
}
public string PropValue
{
get => _propValue;
set
{
_propValue = value;
NotifyPropertyChanged(nameof(PropValue));
}
}
public PointCustomPropViewModel(string propName, string propValue)
{
PropName = propName;
PropValue = propValue;
}
private string _propName;
private string _propValue;
}
在这里,我为主对话框创建了一个测试视图模型,它仅创建具有一些随机参数的点的集合:
public class MainWindowViewModel : ViewModelBase
{
public ObservableCollection<PointViewModel> Points => _points;
public ICollectionView PointsView => _pointsView;
public MainWindowViewModel()
{
_points = new ObservableCollection<PointViewModel>();
_pointsView = CollectionViewSource.GetDefaultView(_points);
Initialize();
}
private void Initialize()
{
var _random = new Random();
for (int _i = 0; _i < 3; _i++)
{
double _randomX = _random.NextDouble();
double _randomY = _random.NextDouble();
double _randomZ = _random.NextDouble();
_points.Add(new PointViewModel($"Point {_i}", _randomX, _randomY, _randomZ));
}
NotifyPropertyChanged(nameof(PointsView));
}
private readonly ObservableCollection<PointViewModel> _points;
private readonly ICollectionView _pointsView;
}
所以这里我创建了3个测试点,每个点还有2个自定义属性。当用户在对话框上执行某些操作时,可以随时添加或删除自定义属性。在开始的任何时候,我们都不知道这些自定义属性的实际数量、名称和值。
但是我们的 DataGrid 应该显示有关所有点的信息,包括有关自定义属性的信息,并且可以编辑每个主要或自定义属性的值。因此,例如,我有一些测试 XAML 代码,其中创建了一个 DataGrid,添加了与 PointsView 属性的 ItemSource 的绑定,以及 PointViewModel 对象中主要 4 列和主要属性之间的绑定:
<DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding PointsView}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
Width="150"
Binding="{Binding Name}"/>
<DataGridTextColumn Header="X"
Width="75"
Binding="{Binding X}"/>
<DataGridTextColumn Header="Y"
Width="75"
Binding="{Binding Y}"/>
<DataGridTextColumn Header="Z"
Width="75"
Binding="{Binding Z}"/>
</DataGrid.Columns>
</DataGrid>
它给了我下一个对话框:
但是如何基于集合生成新列,并为每个点绑定到 CustomProperties 集合中的 Value 属性?例如,我的点有新的自定义属性“Test Prop 1”,该属性的值为“Hello”。因此,我应该生成一个标题为“Test Prop 1”的新列,并且该列中的每一行都应显示相关点的值(在本例中,值将为“Hello”)。例如,当我尝试编辑第一行中此列中的值并将其更改为“Hi”时,它应该在集合点中找到第一个对象,在中找到名称属性 =“Test Prop 1”的 PointCustomPropViewModel 对象其集合 CustomProperties 并将 Value 属性从“Hello”更新为“Hi”。
您需要以某种方式动态生成列,例如根据源集合中第一个
PointCustomPropViewModel
中的 PointViewModel
项目的数量:
var pointViewModel = viewModel.Points[0];
foreach (var customProperty in pointViewModel.CustomProperties)
dataGrid.Columns.Add(new DataGridTextColumn()
{
Header = customProperty.PropName,
Binding = new Binding(customProperty.PropName)
});