我的目标是制作一个ViewModel类,该类可以接受任何类型的对象,并将其分解为可在View中显示和修改的字段的ObservableCollection。我想象中的字段被封装在FieldViewModel中,该字段公开了“字符串FieldName”属性,“对象Value”属性以及Type。
class ViewModel : ViewModelBase
{
public ViewModel(ref object instance)
{
foreach (var field in instance.GetType().GetFields())
{
Fields.Add(new FieldViewModel(instance, field));
}
}
private ObservableCollection<FieldViewModel> _fields = new ObservableCollection<FieldViewModel>();
public ObservableCollection<FieldViewModel> Fields
{
get { return _fields; }
set
{
_fields = value;
OnPropertyChanged();
}
}
}
上面的伪代码是尝试传达我的意图的尝试。当然,需要更多代码来确定字段是否为只读。如果无法做到这一点,您将如何建议您这样做?请告知。
注意:我的特定应用程序只关心字段,而不是属性。我没有创建要在UI中显示的数据模型。
答案 0 :(得分:0)
ExpandoObjects的ObservableCollection可能能够做到这一点。它基本上是一个带有一些语法糖的字典-每个键的每次更改都具有INotifyPropertyChanged通知。其余的将不得不通过反射在原始模型的场上发散。
理想情况下,您不应该回避“强类型化”。此类的存在主要是为了允许与弱类型的Webserve等进行互操作。 Strong Typisaiton是您最大的朋友之一。只需查看此Webcomic的PHP和JavaScript示例,了解原因:http://www.sandraandwoo.com/2015/12/24/0747-melodys-guide-to-programming-languages/
答案 1 :(得分:0)
我已经找到了适合自己目的的方法。可以将其扩展为与属性一起使用,并且仍然需要对用户文本输入进行适当的错误处理。
public class ViewModel : ViewModelBase
{
public ViewModel(object instance)
{
foreach (var field in instance.GetType().GetFields())
{
Fields.Add(new FieldViewModel(instance, field));
}
}
private ObservableCollection<FieldViewModel> _fields = new ObservableCollection<FieldViewModel>();
public ObservableCollection<FieldViewModel> Fields
{
get { return _fields; }
set
{
_fields = value;
OnPropertyChanged();
}
}
}
FieldViewModel如下...
public class FieldViewModel : ViewModelBase
{
private object _instance;
private FieldInfo _fieldInfo;
private Type _fieldType;
public FieldViewModel(object instance, FieldInfo fieldInfo)
{
_instance = instance;
_fieldInfo = fieldInfo;
_fieldType = fieldInfo.FieldType;
IsReadOnly = fieldInfo.IsInitOnly || fieldInfo.IsLiteral;
FieldName = fieldInfo.Name;
TypeName = fieldInfo.FieldType.Name;
}
private bool _IsReadOnly;
public bool IsReadOnly
{
get { return _IsReadOnly; }
private set
{
_IsReadOnly = value;
OnPropertyChanged();
}
}
private string _fieldName;
public string FieldName
{
get { return _fieldName; }
set
{
_fieldName = value;
OnPropertyChanged();
}
}
private string _typeName;
public string TypeName
{
get { return _typeName; }
set
{
_typeName = value;
OnPropertyChanged();
}
}
public object Value
{
get
{
return _fieldInfo.GetValue(_instance);
}
set
{
_fieldInfo.SetValue(_instance, Convert.ChangeType(value, _fieldType));
OnPropertyChanged();
}
}
}
用法看起来像...
Person personInstance = new Person
{
Name = "automagically",
Age = 25,
Height = 185.2,
IsMarried = false
};
ViewModel = new ViewModel(personInstance);
还有视图...
<ItemsControl ItemsSource="{Binding ViewModel.Fields}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding FieldName}" />
<TextBox Grid.Column="1" Text="{Binding Value}" IsReadOnly="{Binding IsReadOnly}"/>
<TextBlock Grid.Column="2" Text="{Binding TypeName}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
看起来像这样...