3

I have a Listbox inside a UserControl to manage different entities with different properties. The UserControl is the same for all entities. I use MVVM and i bind a generic ViewModel as DataContext for the UserControl. I wish to set the ItemTemplate for the Listbox in the container xaml for the UserControl in order to display the entity properties. For the entity "Emlployee" I need to display FullName, for the entity Certifying I need to display CertifyingAuthor and CertifyingDate and so on.

What I need is something similar to that

    <StackPanel Grid.Row="0" Orientation="Vertical">
        <uc:SearchableFromListTextBox ItemTemplateForTheInsideListBox="{StaticResource Something}" ></uc:SearchableFromListTextBox>

Should I add a dependencyProperty ItemTemplateForTheInsideListBoxProperty to the UserControl? And how i could pass it as itemtemplate of the Listbox?

Hope the question is well explained considering my italian native language. thanks

EDIT : I give up. This is a control for keyboard data entry and something similar to autocomplete. Since i am forced to agree to a compromise with MVVM :( i will choose some dirty way to resolve. Thanks to all

  • you really should use typed viewmodels instead of a generic. It makes life much more easy. http://stackoverflow.com/questions/19864891/wpf-mvvm-why-use-contentcontrol-datatemplate-views-rather-than-straight-xaml-w – Mat Nov 04 '16 at 15:43
  • you can also use a template selector. But I still suggest you make different ViewModels and work with the `DataTemplate.TargetType`https://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector(v=vs.110).aspx – Mat Nov 04 '16 at 15:45
  • It seems that using DataTemplates result in design the whole usercontrol. I wish the rest of controls to remain the same. the only difference is on the itemtemplate of the listbox control – Maurizio momix Verde Nov 04 '16 at 16:03
  • I might suggest dependency injection using an interface where your items control template binds to the data context's collection of interfaces. – xtreampb Nov 04 '16 at 19:08

1 Answers1

0

A DataTemplateSelector can do what I think you want. You can define different templates from your user control's XAML, then have the selector choose among them.

Assume these model classes:

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

Your user control's XAML has a ListBox, which in turn uses a template selector (that we'll get to in a moment) -- and also defines different templates for the two different model types:

<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>

The user control's code-behind, where I just assign a list of model objects to the list box (for simplicity):

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

And finally, the template selector. Its two properties were set from the user control's XAML; the logic of SelectTemplate decides which one to apply:

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

And, for completeness, usage of the user control:

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

The end result, where Napoleon is currently selected, and Homer suffers a mouse-over:

enter image description here

Petter Hesselberg
  • 5,062
  • 2
  • 24
  • 42
  • thanks peter for you answer. The fact is your solution needs the usercontrol to be implemented each time new object type comes out. On the other hand i believe the template selector can be moved to a resource dictionary avoiding usercontrol implementation. So i guess i can mark as answer. Thanks again An thanks to @Mat who gave probably same answer but i guess i didn't understand correctly – Maurizio momix Verde Dec 07 '16 at 13:43
  • Replace first "guess" with "Think" and the second one with "Believe". i checked the meaning on wordreference.com :) (hoping it's correct now) – Maurizio momix Verde Dec 07 '16 at 13:52
  • Yes, you can certainly move the template selector to a resource dictionary. I would. :-) – Petter Hesselberg Dec 07 '16 at 14:45