我将
ContentControl
与 DataTemplates 一起使用,其中模板选择器(基于 IDataTemplate
)正在选择要应用的 DataTemplate。
我的模板选择器选择正确的模板并显示它。我的问题是,DataContext 没有从 DataTemplate 中继承到 Control。如果我将 DataTemplate 中的控件代替
ContentControl
,它就会起作用并且 DataContext 会被继承。
如何将
UserControl
的 DataContext 提供给 ContentControl
的 DataTemplate 中的控件?
XAML 代码如下所示:
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:My.Avalonia.ViewModels"
xmlns:v="using:My.Avalonia.Views"
xmlns:dt="using:My.Avalonia.DataTemplates"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="800"
x:Class="My.Avalonia.Views.MainView"
x:DataType="vm:MainViewModel"
>
<ContentControl
Content="{Binding SelectedPage}"
>
<ContentControl.DataTemplates>
<dt:MainViewTemplateSelector>
<DataTemplate x:Key="DisruptionsView">
<v:DisruptionsView />
</DataTemplate>
<!-- More Datatemplates are here -->
</dt:MainViewTemplateSelector>
</ContentControl.DataTemplates>
</ContentControl>
</UserControl>
这是模板选择器:
public class MainViewTemplateSelector : IDataTemplate
{
// This Dictionary should store our shapes. We mark this as [Content], so we can directly add elements to it later.
[Content]
public Dictionary<string, IDataTemplate> AvailableViews { get; } = new Dictionary<string, IDataTemplate>();
// The Keys of the DataTemplates for the views.
private List<string> _ValidViews = new List<string> { "DisruptionsView" }; // Here are more in reality
// Build the DataTemplate here
public Control Build(object? param)
{
var key = param?.ToString(); // Our Keys in the dictionary are strings, so we call .ToString() to get the key to look up
if (key is null) // If the key is null, we throw an ArgumentNullException
{
throw new ArgumentNullException(nameof(param));
}
return AvailableViews[key].Build(param);// finally we look up the provided key and let the System build the DataTemplate for us
}
// Check if we can accept the provided data
public bool Match(object? data)
{
if (data?.GetType() == typeof(string))
{
if (_ValidViews.Contains((string)data))
return true;
return false;
}
else
return false;
}
}
编辑:其他信息
如果我用
ContentControl
替换 ItemsControl
并将 SelectedPage
变量调整为只有一个对象的 string[]
,它就可以工作。它只是破坏了样式,因为 ItemsControl
项目无法使用 *
作为 RowDefinition
高度。
ContentControl
和 ItemsControl
之间的 DataTemplate 处理有什么区别?
这有效:
<ItemsControl
Grid.Row="1"
ItemsSource="{Binding SelectedPage}"
>
<ItemsControl.DataTemplates>
<dt:MainViewTemplateSelector>
<DataTemplate x:Key="DisruptionsView" x:DataType="v:MainView">
<v:DisruptionsView DataContext="{Binding DataContext, ElementName=mv}" />
</DataTemplate>
<DataTemplate x:Key="LinesView">
<v:LinesView />
</DataTemplate>
</dt:MainViewTemplateSelector>
</ItemsControl.DataTemplates>
</ItemsControl>
我找到了解决办法。在
ContentControl
中使用 ContentTemplate
而不是 DataTemplate
。如果这样做,您可以绑定视图的 DataContext
属性,而不会在运行时出现 StackOverflow 异常。
所以我的解决方案如下所示:
添加 x:Name="mv" 到根标签并按如下方式更改 ContentControl
(ContentTemplate
的 Content Control
属性而不是 DataTemplate
以及 DataContext
标签中视图上的 DataTemplate
绑定) :
<ContentControl
Grid.Row="1"
Content="{Binding SelectedPage}"
>
<ContentControl.ContentTemplate>
<dt:MainViewTemplateSelector>
<DataTemplate x:Key="DisruptionsView" x:DataType="v:MainView">
<v:DisruptionsView DataContext="{Binding DataContext, ElementName=mv}" />
</DataTemplate>
<!-- ... -->
</dt:MainViewTemplateSelector>
</ContentControl.ContentTemplate>
</ContentControl>