Home > OS >  How can I pass a different argument to DataTemplateSelector Select method
How can I pass a different argument to DataTemplateSelector Select method

Time:06-28

My data template and Xaml reside in AssemblyX and my view model in AssemblyY but AssemblyX doesn't (and cannot) reference AssemblyY.

Therefore at the moment I can't cast the item object parameter to the type I need as follows for example

public class MyContentTemplateSelector : DataTemplateSelector
{
    public DataTemplate ServiceTemplate { get; set; }
    public DataTemplate GroupTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        MyViewModel vm = item as MyViewModel; //Cannot resolve MyViewModel

        return vm.IsGroup ? GroupTemplate : ServiceTemplate;
    }
}

In reality, the SelectTemplate method doesn't need the whole View Model to work out which template to select, it only needs a boolean property belonging to the ViewModel.

How can I pass the value of a property into the SelectTemplate rather than the whole model?

At the moment in my xaml I've set this up

<internal:MyContentTemplateSelector x:Key="MyContentTemplateSelector" ServiceTemplate="{StaticResource TemplateX}" GroupTemplate="{StaticResource TemplateY}"/>

<Style x:Key="ShippingServiceListStyle" TargetType="ItemsControl" >
    <Setter Property="ItemTemplateSelector"  Value="{StaticResource MyTemplateSelector}" />
    ...
    ...
</Style>

CodePudding user response:

More properly will be move your VMs to the Assembly which can be referenced from your project with DataTemplates.

In case if you haven't ability to move VM's but can modify it.. the solution is implement some interface from shared assembly.

// in shared assembly.. which can be refference from both 
// mentioned assemblies
interface IGroup { bool IsGroup get; }

// AssemblyY
public class MyViewModel : IGroup 
{
     ...
     public bool IsGroup => true; // or false...
     ...

}

// Assembly X
public class MyContentTemplateSelector : DataTemplateSelector
{
    public DataTemplate ServiceTemplate { get; set; }
    public DataTemplate GroupTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)

    {
        IGroup instance =  item as IGroup;         
        return instance.IsGroup ? GroupTemplate : ServiceTemplate;
    }
}

In case if you don't have ability to modify VM the most robust solution - use .NET reflection for get value from the property of passed instance.

public class MyContentTemplateSelector : DataTemplateSelector
{
    public DataTemplate ServiceTemplate { get; set; }
    public DataTemplate GroupTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        Type itemType = item.GetType();

        PropertyInfo propInfo= myType.GetProperty("IsGroup");

        bool isGroup = (bool)propInfo.GetValue(item);

        return isGroup ? GroupTemplate : ServiceTemplate;
    }
}

CodePudding user response:

You can't choose or change what gets passed to the DataTemplateSelector as it's the framework that calls this method for you.

But if you don't have access to the actual view model type, you could use the dynamic keyword to bypass the static type checking performed by the compiler:

public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
    dynamic vm = item;
    return vm.IsGroup ? GroupTemplate : ServiceTemplate;
}
  • Related