首页 > 解决方案 > 在 Xamarin 表单中为 Treeview 创建可绑定属性

问题描述

我需要在我的 xamarin 表单应用程序中使用 Treeview,但是网络上唯一现有的 TreeView 不是免费的(Syncfusion 和 Telerik)。

所以我发现了这个非常有趣的项目:https ://github.com/AdaptSolutions/Xamarin.Forms-TreeView

我发现的唯一问题是 ItemSource 和 SelectedItem 属性不可绑定,因此我不能在 MVVM 模式上使用它。这给我们带来了我的问题,我怎样才能使它们可绑定。

我尝试遵循此文档:https ://docs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/bindable-properties

但仍然没有。任何人都可以帮我吗?谢谢

更新 :

这是 TreeView 类:

public class TreeView : ScrollView
    {
        #region Fields
        private readonly StackLayout _StackLayout = new StackLayout { Orientation = StackOrientation.Vertical };

        //TODO: This initialises the list, but there is nothing listening to INotifyCollectionChanged so no nodes will get rendered
        private IList<TreeViewNode> _RootNodes = new ObservableCollection<TreeViewNode>();
        private TreeViewNode _SelectedItem;
        #endregion

        #region Public Properties

        public TreeViewNode SelectedItem
        {
            get => _SelectedItem;

            set
            {
                if (_SelectedItem == value)
                {
                    return;
                }

                if (_SelectedItem != null)
                {
                    _SelectedItem.IsSelected = false;
                }

                _SelectedItem = value;

                SelectedItemChanged?.Invoke(this, new EventArgs());
            }
        }

      
        public IList<TreeViewNode> RootNodes
        {
            get => _RootNodes;
            set
            {
                _RootNodes = value;

                if (value is INotifyCollectionChanged notifyCollectionChanged)
                {
                    notifyCollectionChanged.CollectionChanged += (s, e) =>
                    {
                        RenderNodes(_RootNodes, _StackLayout, e, null);
                    };
                }

                RenderNodes(_RootNodes, _StackLayout, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset), null);
            }
        }

        #endregion


        #region Constructor
        public TreeView()
        {
            Content = _StackLayout;
        }
        #endregion

        

        #region Private Static Methods
        private static void AddItems(IEnumerable<TreeViewNode> childTreeViewItems, StackLayout parent, TreeViewNode parentTreeViewItem)
        {
            foreach (var childTreeNode in childTreeViewItems)
            {
                if (!parent.Children.Contains(childTreeNode))
                {
                    parent.Children.Add(childTreeNode);
                }

                childTreeNode.ParentTreeViewItem = parentTreeViewItem;
            }
        }
        #endregion

        

        #region Internal Static Methods
        internal static void RenderNodes(IEnumerable<TreeViewNode> childTreeViewItems, StackLayout parent, NotifyCollectionChangedEventArgs e, TreeViewNode parentTreeViewItem)
        {
            if (e.Action != NotifyCollectionChangedAction.Add)
            {

                AddItems(childTreeViewItems, parent, parentTreeViewItem);
            }
            else
            {
                AddItems(e.NewItems.Cast<TreeViewNode>(), parent, parentTreeViewItem);
            }
        }
        #endregion
    }

所以我在这里尝试做的是使 RootNodes 以及之后的 SelectedItem 可绑定。

我所做的只是添加这个,认为它应该可以工作,但显然它没有:

public static readonly BindableProperty RootNodesProperty =
            BindableProperty.Create(nameof(RootNodes), typeof(IList<TreeViewNode>), typeof(TreeView));

        public IList<TreeViewNode> RootNodes
        {
            get => (IList<TreeViewNode>)GetValue(RootNodesProperty);
            set
            {
                SetValue(RootNodesProperty, value);
                _RootNodes = value;
                if (value is INotifyCollectionChanged notifyCollectionChanged)
                {
                    notifyCollectionChanged.CollectionChanged += (s, e) =>
                    {
                        RenderNodes(_RootNodes, _StackLayout, e, null);
                    };
                }

                RenderNodes(_RootNodes, _StackLayout, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset), null);
            }
        }

更新2:这是它的样子 在此处输入图像描述

希望这可以帮助

标签: xamarinxamarin.formsmvvmbindingbindableproperty

解决方案


看来您不需要在ScrollViewItemSource中创建自定义and ,因为 Xamarin Foms 具有包含and的可绑定布局SelectedItemItemsSourceItemTemplateSelector

可绑定布局使派生自 Layout 类的任何布局类都可以通过绑定到项目集合来生成其内容,并且可以选择使用 DataTemplate 设置每个项目的外观。可绑定布局由BindableLayout该类提供,它公开了以下附加属性:

  • ItemsSourceIEnumerable– 指定要由布局显示的项目的集合。
  • ItemTemplate– 指定要应用于布局显示的项目集合中的每个项目的 DataTemplate。
  • ItemTemplateSelector– 指定将用于在运行时为项目选择 DataTemplate 的 DataTemplateSelector。

如果需要使用ScrollView,示例代码如下:

<ScrollView>
 <StackLayout BindableLayout.ItemsSource="{Binding User.TopFollowers}"
             Orientation="Horizontal"
             ...>
    <BindableLayout.ItemTemplate>
        <DataTemplate>
            <controls:CircleImage Source="{Binding}"
                                  Aspect="AspectFill"
                                  WidthRequest="44"
                                  HeightRequest="44"
                                  ... />
        </DataTemplate>
    </BindableLayout.ItemTemplate>
 </StackLayout>
</ScrollView>

推荐阅读