Krogenth
Krogenth
CC#
Created by Krogenth on 8/17/2023 in #help
❔ Avalonia nested ItemsRepeater datatemplates
Well it took a bit of thinking, but the proper approach is a TreeView, with a selector for the TreeDataTemplates. 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