我有一个示例MVVM WPF应用程序,我在为动态加载的模型创建DataTemplates时遇到问题。让我试试解释:
我有以下简化类作为我的模型的一部分,我正在动态加载
public class Relationship
{
public string Category { get; set; }
public ParticipantsType Participants { get; set; }
}
public class ParticipantsType
{
public ObservableCollection<ParticipantType> Participant { get; set; }
}
public class ParticipantType
{
}
public class EmployeeParticipant : ParticipantType
{
public EmployeeIdentityType Employee { get; set; }
}
public class DepartmentParticipant : ParticipantType
{
public DepartmentIdentityType Department { get; set; }
}
public class EmployeeIdentityType
{
public string ID { get; set; }
}
public class DepartmentIdentityType
{
public string ID { get; set; }
}
以下是我的View模型的样子。我创建了一个通用对象Model
属性来公开我的模型:
public class MainViewModel : ViewModelBase<MainViewModel>
{
public MainViewModel()
{
SetMockModel();
}
private void SetMockModel()
{
Relationship rel = new Relationship();
rel.Category = "213";
EmployeeParticipant emp = new EmployeeParticipant();
emp.Employee = new EmployeeIdentityType();
emp.Employee.ID = "222";
DepartmentParticipant dep = new DepartmentParticipant();
dep.Department = new DepartmentIdentityType();
dep.Department.ID = "444";
rel.Participants = new ParticipantsType() { Participant = new ObservableCollection<ParticipantType>() };
rel.Participants.Participant.Add(emp);
rel.Participants.Participant.Add(dep);
Model = rel;
}
private object _Model;
public object Model
{
get { return _Model; }
set
{
_Model = value;
NotifyPropertyChanged(m => m.Model);
}
}
}
然后我尝试创建一个ListBox来专门显示参与者集合:
<ListBox ItemsSource="{Binding Path=Model.Participants.Participant}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Expander Header="IdentityFields">
<!-- WHAT TO PUT HERE IF PARTICIPANTS HAVE DIFFERENT PROPERTY NAMES -->
</Expander>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
问题是:
Employee
或{相应的{1}}属性如果我的具体类型在编译时不知道,但仅在运行时,我怎么能在ListBox中表示这些数据呢?
编辑:添加了我的测试ViewModel类
答案 0 :(得分:2)
您仍然可以为每种类型创建DataTemplate
,但不是使用DataType
声明让它们自动解析,您可以为每个模板创建一个DataTemplateSelector
属性(从{分配) XAML中的{1}}可以将传入的数据项转换为基类并检查属性或以其他方式确定在运行时使用哪个模板。将该选择器分配给StaticResource
,您将获得与ListBox.ItemTemplateSelector
给您的相似的行为。
答案 1 :(得分:0)
这不是一个好的视图模型。您的视图模型应该以视图为中心,而不是以业务为中心。因此,创建一个可以从可视角度处理所有四种情况的类,然后将业务类桥接到该视图模型。
编辑:
解决你的代码:
<ListBox ItemsSource="{Binding Path=Model.Participants}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Expander Header="IdentityFields">
<TextBlock Text={Binding Id} />
<TextBlock Text={Binding Name} />
</Expander>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
我更改了绑定,我认为这是一个错误?
我会为参与者创建一个ViewModel:
public class Participant_VM : ViewModelBase
{
private string _name = string.Empty;
public string Name
{
get
{
return _name ;
}
set
{
if (_name == value)
{
return;
}
_name = value;
RaisePropertyChanged(() => Name);
}
private string _id= string.Empty;
public string Id
{
get
{
return _id;
}
set
{
if (_id== value)
{
return;
}
_id = value;
RaisePropertyChanged(() => Id);
}
}
}
答案 2 :(得分:0)
按如下方式修改ListBox
。
<ListBox ItemsSource="{Binding Model.Participants.Participant}">
<ListBox.Resources>
<DataTemplate DataType="{x:Type loc:DepartmentParticipant}">
<Grid>
<TextBlock Text="{Binding Department.ID}"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type loc:EmployeeParticipant}">
<Grid>
<TextBlock Text="{Binding Employee.ID}"/>
</Grid>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Expander Header="IdentityFields">
<!-- WHAT TO PUT HERE IF PARTICIPANTS HAVE DIFFERENT PROPERTY NAMES -->
<ContentPresenter Content="{Binding }"/>
</Expander>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
编辑:
loc指的是DepartmentParticipant
和EmployeeParticipant
所在的命名空间。希望您熟悉添加名称空间。