我正在努力解决如何引用/绑定到CollectionView
的DataTemplate
中的当前项。
我已经看过像this这样的问题,并且 * 认为 * 我可以将解决方案应用于MAUI,因为它和WPF都使用XAML,但Intellisense抱怨{Binding /}
不是有效的绑定路径。执行more digging后发现我应该使用{Binding .}
。所以我尝试了,但是,试图运行我的应用程序的结果是它甚至没有加载在所有。
我的xaml现在看起来像这样:TreeNode.xaml
<maui:ReactiveContentView
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:maui="clr-namespace:ReactiveUI.Maui;assembly=ReactiveUI.Maui"
xmlns:vm="clr-namespace:turquoise_frontend.Controls"
xmlns:math="clr-namespace:HexInnovation;assembly=MathConverter.Maui"
x:TypeArguments="vm:TreeNodeModel"
x:DataType="vm:TreeNodeModel"
x:Class="turquoise_frontend.Controls.TreeNode" x:Name="this">
<VerticalStackLayout x:Name="sl2">
<!-- stuff omitted due to being irrelevant here... -->
<CollectionView ItemsSource="Children" x:Name="_ChildrenStackLayout" CanMixGroups="True" CanReorderItems="True" ReorderCompleted="_ChildrenStackLayout_ReorderCompleted">
<CollectionView.ItemTemplate>
<DataTemplate>
<vm:TreeNode/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
</maui:ReactiveContentView>
字符串
我猜测,运行时将{Binding .}
解释为当前xaml文件所表示的对象,而不是ItemTemplate
所表示的对象,从而导致了无限递归。
那么,如果我想创建一个可以利用CollectionView
并且不会无限循环的递归布局,我应该写什么呢?我现在想做的事有可能吗TreeNode.xaml.cs
public partial class TreeNode : ReactiveContentView<TreeNodeModel>
{
public double? IndentWidth => Depth * SpacerWidth;
public double? PaddingWidth => IndentWidth + 30;
public int SpacerWidth { get; } = 40;
private int? Depth => ViewModel?.Value.Depth ?? 0;
public string ExpandText { get => (ViewModel?.Children?.Count ?? 0) > 0 ? "▷" : ""; }
public TreeNode(TreeNodeModel tnm)
{
this.WhenAnyValue(x => x.ViewModel.isExpanded).ObserveOn(RxApp.MainThreadScheduler).Subscribe(b =>
{
_ChildrenStackLayout.IsVisible = b;
});
this.WhenAnyValue(b => b.ViewModel.selected).ObserveOn(RxApp.MainThreadScheduler).Subscribe(a =>
{
SelectionBoxView.IsVisible = a;
});
this.WhenAnyValue(b => b.ViewModel).ObserveOn(RxApp.MainThreadScheduler).WhereNotNull().Subscribe(vm =>
{
vm.Children.CollectionChanged += (o, e) =>
{
_SpacerBoxView.WidthRequest = IndentWidth ?? 0;
};
});
BindingContext = ViewModel = tnm;
InitializeComponent();
}
}
型TreeNodeModel.cs
public class TreeNodeModel : ReactiveObject
{
private ITreeNode _value;
private ObservableCollection<TreeNodeModel> _children;
private TreeNodeModel? _parent;
private bool _toggled;
private bool _selected;
private bool _expanded;
private string contract;
[Reactive]
public ITreeNode Value { get => _value; set => this.RaiseAndSetIfChanged(ref _value, value); }
[Reactive]
public TreeNodeModel? Parent
{
get => _parent; set
{
_parent = value;
Value.Parent = value?.Value;
}
}
[Reactive]
public ObservableCollection<TreeNodeModel> Children
{
get
{
var nc = new ObservableCollection<TreeNodeModel>();
foreach (var i in Value.Children ?? new ObservableCollection<ITreeNode>())
{
var b = new TreeNodeModel(i, this.contract)
{
Tree = this.Tree
};
b.Parent = this;
nc.Add(b);
}
return nc;
}
}
public TreeNodeModel Root
{
get
{
TreeNodeModel top = this;
do
{
if (top.Parent != null)
top = top.Parent;
else break;
} while (top != null);
return top ?? this;
}
}
[Reactive]
public bool isExpanded { get => _expanded; set => this.RaiseAndSetIfChanged(ref _expanded, value); }
[Reactive] public bool Toggled { get => _toggled; set => this.RaiseAndSetIfChanged(ref _toggled, value); }
public TreeModel Tree { get; set; }
[Reactive]
public bool selected { get => _selected; set => this.RaiseAndSetIfChanged(ref _selected, value); }
public TreeNodeModel(ITreeNode val, string contract)
{
this.contract = contract;
Toggled = val.Toggled;
selected = false;
isExpanded = false;
_value = val;
if (val.Parent != null)
_parent = new TreeNodeModel(val.Parent, contract) {
Tree = this.Tree
};
this.WhenAnyValue(b => b.Toggled).Subscribe(a =>
{
_value.Toggled = a;
});
this.WhenAnyValue(b => b.isExpanded);
this.WhenAnyValue(b => b.Toggled);
this.WhenAnyValue(b => b.selected);
}
}
型ITreeNode
接口
public interface ITreeNode
{
public object Value { get; set; }
public ObservableCollection<ITreeNode> Children { get; }
public ITreeNode? Parent { get; set; }
public int Depth { get; }
public int ID();
public bool IsBranch { get; }
public string AsString { get; }
public bool Toggled { get; set; }
public void Add(ITreeNode tn, int index);
public void Add(ITreeNode tn);
public void Remove(ITreeNode tn);
public void Remove(int index);
public bool Equals(ITreeNode other);
public event NotifyCollectionChangedEventHandler NotifyCollectionChanged;
}
型
2条答案
按热度按时间au9on6nz1#
让我们来看看这一部分:
字符串
注意“B”是如何调用构造函数的:
型
所以,这里发生了什么:
“i”(这是ITreeNode,提醒您正确命名变量)被放入构造函数中。
我们正在构造“B”(这是TreeNodeModel,同样的提醒)
如果我有父母
构造函数被再次调用,并且父级被设置。在这一行:
型
然而,在这个递归完成之后,我们从这一行开始:
型
到这一行:
型
我们意识到有一半的代码什么也没做。而新构建的孩子和他们的父母(以及对该事件的订阅)会发生什么并不是很清楚。
还有这个:
型
是不行。
i86rm4rw2#
DataTemplate中的{Binding .}将表示ItemsSource的单击项。