I'm trying to data bind a list to a collection of type ObservableCollection<IMyInterface>. The data binding works well, but the catch seems to be that I have to create a data template with the type set to the concrete type of the objects in the collection rather than the interface type. This is a problem since some of the items in the list are supplied by plug-ins to the base application and I don't necessarily know the concrete type. Everything I need to populate the data template is in the interface.
My question comes down to Is there a way to specify the template based on the collection type rather than the concrete object type or some other way to get this to work. It doesn't seem like a completely unreasonable thing to want to do.
Any help will be greatly appreciated.

Data templates and interfaces
Jean-Michel Herve
public interface IProjectItem
{
string Name
{
get;
set;
}
}
A Profile is one of the data types that the code has to process. It implements IProjectItem and adds a bunch of properties for x,y,z positions in space of survey points and some other location information.
public class Profile : IProjectItem
{
// lots of other code here
private string name = "Profile";
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
}
The main application has a class with some top level data and a collection of all of the IProjectItems that have been loaded.
public class DataStore
{
ObservableCollection<IProjecItem> dataItems = new ObservableCollection<IProjectItem>();
public ObservableCollection<IProjectItem> DataItems
{
get
{
return dataItems;
}
}
}
I have a list view that should display all of the items in the DataItems collection. I've set the data context correctly since the ListView shows the right number of items, but it just shows the result of calling ToString() on the Profile objects i.e. (MyNamespace.Profile).
<ListView x:Name="DataTree" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Stretch" ItemsSource="{Binding Path=DataItems}">
Here is the data template that I'm trying to use to populate the list. I've reduced it down to just trying to extract the name from the interface. I get the desired results if I change the x:Type from IProjectItem to Profile (the concrete class). It isn't possible to make a list of all the possible types since I want to be able to add new types by implementing the IProjectItem interface and loading the assembly as a plugin in the application.
<Window.Resources>
<DataTemplate DataType="{x:Type app:IProjectItem}">
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</Window.Resources>
It seems that what is happening is that the DataTemplates are matched against the type of the item rather than the type parameter of the collection. If I add a base class that implements the IProjectItem interface and change the DataTemplate to match the base class type I get the desired results.
I'd like to be able to specify a DataTemplate that matches an interface rather than a class. Is it actually possible to do what I'm trying to do If not, is this something that might get added in later
I didn't really want to use an abstract base class instead of an interface since it "uses up" my one inheritance opportunity that I may need in my data model just to make things convienient for DataBinding. I can work around this by creating a separate view model on top of the data model, but it does add a good bit of work.
Any help/advice is appreciated.
Thanks.
Orest
Hi Wayne,
Can you provide a few snips of code, might help see the problem further.
Thanks
Andy
StevePO
I can accomplish what I want using the SelectTemplate method I believe and not even have to use reflection. My ObservableCollection I'm trying to bind to is templatized with the interface type and I have a data template that matches that interface type. It turns the SelectTemplate call into just a return statement.
I just didn't think of using the SelectTemplate method to accomplish what I wanted as I'm still pretty new to WPF. It is going to be as large of a change for UI develpment as moving from MFC to WinForms was but it will be well worth the effort.
Wayne
John_NSI
Wayne,
Here is a sample of what I explained in my last post, about TemplateSelector: http://www.beacosta.com/Forum/DataTemplatingInterfaces.zip. I hope this will make it easier for you and others to understand how to data template based on the interface type.
Yes, I agree it is a big change for developers with experience in other technologies to start using WPF, it's a new way of thinking. Hopefully we will be able to ease that process and you guys will find it was worth it the effort.
Thanks,
Bea
gregorylambert
Hi Wayne,
The data binding team discussed adding support for interfaces a while ago but ended up not implementing it because we could not come up with a good design for it. The problem was that interfaces don't have a hierarchy like object types do. Consider the scenario where your data source implements both IMyInterface1 and IMyInterface2 and you have DataTemplates for both of those interfaces in the resources: which DataTemplate do you think we should pick up
When doing implicit data templating for object types, we first try to find a DataTemplate for the exact type, then for its parent, grandparent and so on. There is very well defined order of types for us to apply. When we talked about adding support for interfaces, we considered using reflection to find out all interfaces and adding them to the end of the list of types. The problem we encountered was defining the order of the interfaces when the type implements multiple interfaces.
The other thing we had to keep in mind is that reflection is not that cheap, and this would decrease our perf a little for this scenario.
So what's the solution You can't do this all in XAML, but you can do it easily with a little bit of code. The ItemTemplateSelector property of ItemsControl can be used to pick which DataTemplate you want to use for each item. In the SelectTemplate method for your template selector, you receive as a parameter the item you will template. Here, you can check for what interface it implements and return the DataTemplate that matches it.
Let me know if this helps.
Bea
ASHegazy
Here is one way to do it.
public interface IProjectItem
{
string Name
{
get;
set;
}
}
public class BaseProjectItem : IProjectItem
{
String Name{/*get and set*/}
}
Have all concrete IProjectItem objects inherit from BaseProjectItem. The container would then hold BaseProjectItem objects. Not very elegant but it worked on my machine.
Tron Eivin
What I'm thinking of doing is creating a ViewProjectItem class that implements the IProjectItem interface and has a single member that holds an instance of the "real" IProjectItem and delegates all of the methods to the wrapped instance. Not necessarily the most elegant solution, but I need the one shot at inheritance for behavior other than the ProjectItem interface which mitigates against requiring a BaseProjectItem class in my data heirarchy. I do have a BaseProjectItem class to provide a common implementation of the IProjectItem interface for derived classes that wish to take advantage of it, but can't really require that all items inherit from it.