Krogenth
❔ Avalonia nested ItemsRepeater datatemplates
Well it took a bit of thinking, but the proper approach is a
TreeView
, with a selector for the TreeDataTemplate
s.
Something like the following should work, where some inheriting objects have children, while others do not:
namespace Types;
public interface BaseInterface
{
...
};
// define objects
public class InheritingObjectType : BaseInterface
{
...
public List<BaseInterface> NestedObjects {get;}
};
public class OtherInheritingObjectType : BaseInterface
{
...
};
// other implementing classes
namespace Types;
public interface BaseInterface
{
...
};
// define objects
public class InheritingObjectType : BaseInterface
{
...
public List<BaseInterface> NestedObjects {get;}
};
public class OtherInheritingObjectType : BaseInterface
{
...
};
// other implementing classes
namespace viewmodels;
public class ObjectsViewModel
{
// collection to feed TreeView
public ObservableCollection<BaseInterface> Items {get;}
};
namespace viewmodels;
public class ObjectsViewModel
{
// collection to feed TreeView
public ObservableCollection<BaseInterface> Items {get;}
};
// tree data template selector
public class SomeSelector : ITreeDataTemplate
{
[Content]
public Dictionary<string, IDataTemplate> Templates { get; private set; } = new();
public InstancedBinding ItemsSelector(object item)
{
if (item is BaseInterface obj)
{
return ((TreeDataTemplate)Templates[obj.GetType().Name]).ItemsSelector(item);
}
else
{
return null;
}
}
public IControl Build(object data) =>
Templates[data.GetType().Name].Build(data);
public bool Match(object data)
=> data is BaseInterface && Templates.ContainsKey(data.GetType().Name);
}
// tree data template selector
public class SomeSelector : ITreeDataTemplate
{
[Content]
public Dictionary<string, IDataTemplate> Templates { get; private set; } = new();
public InstancedBinding ItemsSelector(object item)
{
if (item is BaseInterface obj)
{
return ((TreeDataTemplate)Templates[obj.GetType().Name]).ItemsSelector(item);
}
else
{
return null;
}
}
public IControl Build(object data) =>
Templates[data.GetType().Name].Build(data);
public bool Match(object data)
=> data is BaseInterface && Templates.ContainsKey(data.GetType().Name);
}
<TreeView Items="{Binding Items}">
<TreeView.DataTemplates>
<selectors:SomeSelector>
<TreeDataTemplate x:Key="InheritingObjectType"
DataType="{x:Type types:InheritingObjectType}"
ItemsSource="{Binding NestedObjects}">
<!-- whatever needs rendered -->
</TreeDataTemplate>
<TreeDataTemplate x:Key="OtherInheritingObjectType"
DataType="{x:Type types:OtherInheritingObjectType}">
<!-- whatever needs rendered -->
</TreeDataTemplate>
<!-- other datatemplates -->
</selectors:MapOpcodeSelector>
</TreeView.DataTemplates>
</TreeView>
<TreeView Items="{Binding Items}">
<TreeView.DataTemplates>
<selectors:SomeSelector>
<TreeDataTemplate x:Key="InheritingObjectType"
DataType="{x:Type types:InheritingObjectType}"
ItemsSource="{Binding NestedObjects}">
<!-- whatever needs rendered -->
</TreeDataTemplate>
<TreeDataTemplate x:Key="OtherInheritingObjectType"
DataType="{x:Type types:OtherInheritingObjectType}">
<!-- whatever needs rendered -->
</TreeDataTemplate>
<!-- other datatemplates -->
</selectors:MapOpcodeSelector>
</TreeView.DataTemplates>
</TreeView>
4 replies