1

I've set up a generic dialog window that takes in a viewmodel and title, to then display according to the window's XAML.

For example, this code sets the title and data context of the window and shows it:

public void ShowWindow(object viewModel, string title)
{
    var win = new DialogWindow()
    {
        Title = title,
        DataContext = viewModel
    };
    win.Show();
}

The window's codebehind contains nothing of relevance, but the XAML for its content presenter looks like:

<ContentPresenter x:Name="DialogPresenter" Content="{Binding}">
    <ContentPresenter.Resources>
        <DataTemplate DataType="{x:Type i:IMyInterface}" >
            <c:MyInterfacesControl/>
        </DataTemplate>
    </ContentPresenter.Resources>
</ContentPresenter>

The problem is that the datatemplate doesn't fire, as the viewmodel passed in is an implementation of that interface. However, I want the code to detect whether the viewmodel implements that, and use the template accordingly.

I've thought of one or two ways around the problem by using converters, for example checking whether something is an implementation of a converter parameter.

But is there a simpler way here?

Edit: This is not the same as the question suggested in the comments (Edit 2: that's now gone); I won't know the interface type (many different ones may be passed in), and instead have a data context of type object to work with.

Dan
  • 1,130
  • 2
  • 20
  • 38
  • @Sinatr AFAICT, that question uses a property of the interface type. I won't know the interface type (many different ones may be passed in), and instead have a data context of type `object` to work with. – Dan Jul 28 '17 at 14:12
  • Many work-arounds exist, but the basic functionality you want isn't supported. See marked duplicate. In some cases, you will need help accessing interface properties. See https://stackoverflow.com/questions/327984/wpf-databinding-to-interface-and-not-actual-object-casting-possible for info about doing that. Another work-around not mentioned is, if you are able to use `abstract` classes instead of interfaces (i.e. you can guarantee your model objects won't implement more than one, and you can insert the `abstract` class in the inheritance tree), template selection would work with that. – Peter Duniho Jul 28 '17 at 23:42

1 Answers1

1

DataTemplate doesn't work with types as interfaces, you should normally use it with concrete type.

If you have interfaces defined

public interface IA
{
    string A { get; set; }
}

and concrete type implementing it:

public class AA : IA
{
    public string A { get; set; }
}

Then following data template will not be used, when passing new A();

<DataTemplate DataType="{x:Type local:IA}">
    <TextBlock Text="{Binding A}" />
</DataTemplate>

Instead you will see something like

Application.AA

Solution 1

You can use concrete type and then everything will work:

<DataTemplate DataType="{x:Type local:AA}">
    <TextBlock Text="{Binding A}" />
</DataTemplate>

Solution 2

Use property of interface type and bind to it (not to concrete type), this is described in this answer.

Note: you can use same name of property to return different interface (the one to choose data template) in your concrete types.

Solution 3

You can use template selector. This is really simple, give keys to data template:

<DataTemplate x:Key="ia">
    <TextBlock Text="{Binding A}" />
</DataTemplate>

and choose which one to use in code:

public class TemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is IA)
            return (DataTemplate)((FrameworkElement)container).FindResource("ia");

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

ContentControl has ContentTemplateSelector property, don't use ContentPresenter for this.

Sinatr
  • 20,892
  • 15
  • 90
  • 319