ListBox DataTemplate用于动态加载的类型

时间:2013-02-12 15:27:15

标签: wpf mvvm listbox

我有一个示例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>

问题是:

  1. 我不知道如何创建一个可以处理两种参与者类型的模板,在这种情况下我可以有EmployeeParticipant或DepartmentParticipant,因此根据这一点,数据绑定路径将设置为Employee或{相应的{1}}属性
  2. 我虽然为每种类型创建一个DataTemplate(例如x:Type EmployeeParticipant),但问题是我的模型中的类是在运行时动态加载的所以VisualStudio会抱怨这些类型没有' t存在于当前的解决方案中。
  3. 如果我的具体类型在编译时不知道,但仅在运行时,我怎么能在ListBox中表示这些数据呢?

    编辑:添加了我的测试ViewModel类

3 个答案:

答案 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指的是DepartmentParticipantEmployeeParticipant所在的命名空间。希望您熟悉添加名称空间。