Avalonia UI 在 ContentControls DataTemplate 中设置控件的 DataContext

问题描述 投票:0回答:1

我将

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>
c# avalonia
1个回答
0
投票

我找到了解决办法。在

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>
© www.soinside.com 2019 - 2024. All rights reserved.