我正在学习 Avalonia,并尝试根据自定义对象的 ObservableCollection 中的属性在两个不同的 DataTemplate 之间进行 ItemsControl 切换。
我有一个名为“Parameters”的
ObservableCollection<Parameter>
,其中“Parameter”定义如下:
public class Parameter
{
public Parameter(string value = "") {
if (value.ToLower() == "switch") {
IsBool = true;
}
}
private string _name;
public string Name {
get { return _name; }
set {
_name = value;
}
}
public bool IsBool { get; set; } = false;
}
这是我的 XAML 代码,其中定义了 ItemsControl:
<ItemsControl Grid.IsSharedSizeScope="True" ItemsSource="{Binding Parameters}">
<ItemsControl.ItemTemplate>
<Binding Path="IsBool">
<resources:ParameterTemplateSelector>
<DataTemplate x:Key="true">
<Grid Margin="20 10 ">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Label" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" MaxWidth="600" />
</Grid.ColumnDefinitions>
<Label Content="{ReflectionBinding Path=Name}" VerticalContentAlignment="Center"
HorizontalContentAlignment="Right" />
<ToggleSwitch Grid.Column="2"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="false">
<Grid Margin="20 10 ">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Label" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" MaxWidth="600" />
</Grid.ColumnDefinitions>
<Label Content="{ReflectionBinding Path=Name}" VerticalContentAlignment="Center"
HorizontalContentAlignment="Right" />
<AutoCompleteBox Name="AutoCompleteBox" Grid.Column="2"
HorizontalAlignment="Stretch"/>
</Grid>
</DataTemplate>
</resources:ParameterTemplateSelector>
</Binding>
</ItemsControl.ItemTemplate>
</ItemsControl>
这是“ParameterTemplateConverter”(尽管没有它代码会给出相同的错误):
public class ParameterTemplateSelector : IDataTemplate
{
[Content]
public Dictionary<bool, IDataTemplate> AvailableTemplates { get; } = new Dictionary<bool, IDataTemplate>();
public Control Build(object? param)
{
var key = param?.Equals(true);
if (key == null) {
throw new ArgumentNullException(nameof(param));
}
return AvailableTemplates[key.Value].Build(param);
}
public bool Match(object? data)
{
var key = data?.Equals(true);
return data is bool
&& key != null
&& AvailableTemplates.ContainsKey(key.Value);
}
}
理想情况下,这将为每个值为 true 的“IsBool”创建一个带有 ToggleSwitch 的网格,并为其余的创建一个带有 AutoCompleteBox 的网格,但尝试运行代码会出现此错误,大概是在“IsBool”绑定属性上:
错误 AVLN:0004 Avalonia:转换节点 XamlX.Ast.XamlAstObjectNode 时出现内部编译器错误: System.ArgumentOutOfRangeException:索引超出范围。必须为非负数且小于集合的大小。 (参数“索引”)我觉得这是因为集合在运行时为空,但如果我在其他地方使用任何“参数”属性,我不会收到此错误,并且由于我无法在运行时之前填充集合,所以我不太清楚确定如何解决这个问题。
首先,
<resources:ParameterTemplateSelector>
不应在绑定内声明。 XAML 应该如下所示:
<ItemsControl ItemsSource="{Binding Parameters}" ...>
<ItemsControl.ItemTemplate>
<resources:ParameterTemplateSelector>
<DataTemplate x:Key="true">
...
</DataTemplate>
<DataTemplate x:Key="false">
...
</DataTemplate>
</resources:ParameterTemplateSelector>
</ItemsControl.ItemTemplate>
</ItemsControl>
其次,ParameterTemplateSelector
的代码应该是这样的:
public class ParameterTemplateSelector : IDataTemplate
{
[Content]
public Dictionary<string, IDataTemplate> AvailableTemplates { get; } = new Dictionary<string, IDataTemplate>();
public Control Build(object? data)
{
var parameter = (Parameter)data;
return AvailableTemplates[parameter.IsBool.ToString().ToLower()].Build(data);
}
public bool Match(object? data)
{
return data is Parameter;
}
}