在用户控件内设置列表框的项模板

3
我有一个包含不同属性实体的列表框(Listbox),该列表框位于UserControl内。对于所有实体,该UserControl都是相同的。 我使用MVVM,并将通用ViewModel绑定为UserControl的DataContext。 为了显示实体属性,我希望在容器xaml中设置Listbox的ItemTemplate。例如对于实体“Employee”,我需要显示FullName,对于实体“Certifying”,我需要显示CertifyingAuthor和CertifyingDate等等。
我需要的是类似于这个样子的东西:
    <StackPanel Grid.Row="0" Orientation="Vertical">
        <uc:SearchableFromListTextBox ItemTemplateForTheInsideListBox="{StaticResource Something}" ></uc:SearchableFromListTextBox>

我应该为UserControl添加一个dependencyProperty ItemTemplateForTheInsideListBoxProperty吗?我如何将它作为Listbox的itemtemplate传递? 希望我的问题已经很清楚了,考虑到我的意大利母语。谢谢。 编辑:我放弃了。这是一个键盘数据输入控件,类似于自动完成。由于我被迫接受与MVVM妥协:(我会选择一些肮脏的方法来解决。感谢所有人。

你真的应该使用类型化的视图模型而不是通用的。这会让生活变得更加轻松。https://dev59.com/72Ij5IYBdhLWcg3wzIFo - Mat
你也可以使用模板选择器。但我仍建议您创建不同的ViewModel并使用DataTemplate.TargetType进行操作。https://msdn.microsoft.com/zh-cn/library/system.windows.controls.datatemplateselector(v=vs.110).aspx - Mat
似乎使用数据模板会导致整个用户控件的设计发生变化。我希望其余控件保持不变,唯一的区别只在于ListBox控件的ItemTemplate。 - Maurizio momix Verde
我建议使用接口进行依赖注入,其中您的项控件模板绑定到数据上下文的接口集合。 - xtreampb
1个回答

0
一个 DataTemplateSelector 可以实现你想要的功能。你可以在用户控件的 XAML 中定义不同的模板,然后让选择器在它们之间进行选择。
假设这些是模型类:
public class Employee
{
    public Employee(string fullName)
    {
        FullName = fullName;
    }

    public string FullName { get; }
}

public class Certifying
{
    public Certifying(string certifyingAuthor, DateTime certifyingDate)
    {
        CertifyingAuthor = certifyingAuthor;
        CertifyingDate = certifyingDate;
    }

    public string CertifyingAuthor { get; }

    public DateTime CertifyingDate { get; }
}

你的用户控件的XAML中有一个ListBox,它反过来使用了一个模板选择器(我们稍后会讲到)-- 并且为两种不同的模型类型定义了不同的模板:

<UserControl
    x:Class="WPF.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPF"
    >
    <Grid>
        <ListBox x:Name="listBox">
            <ListBox.ItemTemplateSelector>
                <local:MyTemplateSelector>
                    <local:MyTemplateSelector.EmployeeTemplate>
                        <DataTemplate DataType="local:Employee">
                            <TextBlock
                                Foreground="Red"
                                Text="{Binding FullName}"
                            />
                        </DataTemplate>
                    </local:MyTemplateSelector.EmployeeTemplate>
                    <local:MyTemplateSelector.CertifyingTemplate>
                        <DataTemplate DataType="local:Certifying">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="120" />
                                    <ColumnDefinition Width="Auto" />
                                </Grid.ColumnDefinitions>
                                <TextBlock
                                    Foreground="Blue"
                                    Text="{Binding CertifyingAuthor}"
                                />
                                <TextBlock
                                    Grid.Column="1"
                                    Foreground="Green"
                                    Text="{Binding CertifyingDate}"
                                />
                            </Grid>
                        </DataTemplate>
                    </local:MyTemplateSelector.CertifyingTemplate>
                </local:MyTemplateSelector>
            </ListBox.ItemTemplateSelector>
        </ListBox>
    </Grid>
</UserControl>

用户控件的代码后台,我只是将一个模型对象列表分配给列表框(为了简单起见):
public partial class UserControl1
{
    public UserControl1()
    {
        InitializeComponent();
        listBox.ItemsSource = new List<object>
            {
                new Employee("Donald Duck"),
                new Certifying("Mickey Mouse", DateTime.Now),
                new Employee("Napoleon Bonaparte"),
                new Certifying("Homer Simpson", DateTime.Now - TimeSpan.FromDays(2)),
            };
    }
}

最后,是模板选择器。它的两个属性是从用户控件的XAML中设置的;SelectTemplate的逻辑决定应用哪一个:
public class MyTemplateSelector : DataTemplateSelector
{
    /// <summary>
    /// This property is set from XAML.
    /// </summary>
    public DataTemplate EmployeeTemplate { get; set; }

    /// <summary>
    /// This property is set from XAML.
    /// </summary>
    public DataTemplate CertifyingTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is Employee)
        {
            return EmployeeTemplate;
        }

        if (item is Certifying)
        {
            return CertifyingTemplate;
        }

        return base.SelectTemplate(item, container);
    }
}

为了完整起见,使用用户控件:

<Grid>
    <wpf:UserControl1 />
</Grid>

最终结果是拿破仑当前被选择,而荷马遭受悬停影响:

enter image description here


谢谢Peter的回答。事实上,您的解决方案需要在每次出现新对象类型时实现UserControl。另一方面,我相信可以将模板选择器移至资源字典,避免实现UserControl。 所以我想我可以标记为答案。 再次感谢 并感谢@Mat,他可能给出了同样的答案,但我想我没有正确理解。 - Maurizio momix Verde
将第一个“guess”替换为“Think”,第二个替换为“Believe”。我在wordreference.com上检查了含义 :)(希望现在是正确的) - Maurizio momix Verde
是的,您肯定可以将模板选择器移动到资源字典中。我会这样做。 :-) - Petter Hesselberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接