【问题标题】:ListBox DataTemplate for dynamically loaded type动态加载类型的 ListBox DataTemplate
【发布时间】:2013-01-27 22:58:48
【问题描述】:

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

这是我的视图模型的样子。我创建了一个通用对象 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. 我不知道如何创建一个可以处理这两种类型的 ParticipantTypes 的模板,在这种情况下,我可以有 EmployeeParticipant 或 DepartmentParticipant,因此根据此,数据绑定路径将设置为 EmployeeDepartment相应的属性
  2. 虽然我想为每种类型创建一个 DataTemplate(例如 x:Type EmployeeParticipant),但问题是我的模型中的类是在运行时动态加载的,所以 VisualStudio 会抱怨这些类型没有t 存在于当前解决方案中。

如果我的具体类型在编译时未知,而仅在运行时未知,我如何在 ListBox 中表示这些数据?

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

【问题讨论】:

标签: wpf mvvm listbox


【解决方案1】:

您仍然可以为每种类型创建一个DataTemplate,但不是使用DataType 声明让它们自动解析,您可以为每个模板创建一个带有属性的DataTemplateSelector(从XAML 中的StaticResource 分配)可以将传入的数据项转换为基类并检查属性或以其他方式确定在运行时使用哪个模板。将该选择器分配给ListBox.ItemTemplateSelector,您将获得与DataType 相似的行为。

【讨论】:

  • 在评估了所有不同的选项之后,我认为您的答案是根据我的要求更好地完成这项工作。我只是在我的ItemTemplateSelector 中检查项目对象类型,并基于它返回一个 DataTemplate。我将根据您的建议用我的最终方法更新问题。感谢您的帮助!
【解决方案2】:

这不是一个好的视图模型。您的视图模型应该以视图为中心,而不是以业务为中心。因此,创建一个可以从视觉角度处理所有四种情况的类,然后将您的业务类连接到该视图模型。


编辑:

处理您的代码:

<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);
        }

    }
}

【讨论】:

  • 很高兴你提出来。我将整个 ViewModel 类添加到问题中。
  • 当您说“创建一个可以从视觉角度处理所有四种情况的类”时,您的意思是 XAML 视图 @Shlomo?
【解决方案3】:

修改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 的命名空间。希望您熟悉添加命名空间。

【讨论】:

  • 谢谢,就像我说的,我的模型类型是在运行时加载的,所以我无法在设计时使用这些类型。即使我在 WPF 项目中添加对我的模型 dll 的引用,它也会添加命名空间:xmlns:loc="clr-namespace:;assembly=PIM_SBP.TransactionPolicy",但仍然无法正常工作。我得到:'类型引用不能找到一个名为 DepartmentParticipant 的公共类型'
猜你喜欢
  • 1970-01-01
  • 2012-02-28
  • 1970-01-01
  • 2021-04-22
  • 1970-01-01
  • 1970-01-01
  • 2014-05-21
  • 2011-07-13
  • 1970-01-01
相关资源
最近更新 更多