【问题标题】:Xamarin Custom BindableProperty with ObservableCollection带有 ObservableCollection 的 Xamarin 自定义 BindableProperty
【发布时间】:2016-04-14 08:06:44
【问题描述】:

我正在尝试创建一个“桌面”页面,以显示图标(程序)。

现在的基本思想是使用 3x3 网格,每个单元格代表一个图标点。

我过去只是直接从我的 ViewModel 调用 View,但我想忠于 MVVM,并认为我会尝试在自定义 Grid 类中使用 DataBinding 和 ObservableCollection 让它工作。

这是我的代码

ViewModel.cs

/*
ViewModel for the DashboardView
*/
public class DashboardViewModel : ViewModelBase
{
    INavigationService navigation;
    INetworkService network;

    public DashboardViewModel(INavigationService _navigation,
           INetworkService _network
           )
    {
        navigation = _navigation;
        network = _network;
        //modelService = _modelService;

        Startup();
    }

    /*
    Called when the application starts
    */
    public async void Startup()
    {
        //Bunch of network mumbojumbo that returns a bunch of services as JSON

        IList<JToken> results = result["data"]["services"].Children().ToList();
        foreach (JToken r in results)
        {
            ServiceModel temp = JsonConvert.DeserializeObject<ServiceModel>(r.ToString());
            Services.Add(temp);
            Debug.WriteLine(r);
        }
    }

    /*
    Holds all services displayed on the dashboard
    */
    public IList<ServiceModel> Services { get; } = new ObservableCollection<ServiceModel>();

这是View.cs中的相关代码

        serviceBoard = new DashboardDesktop()
        {
            VerticalOptions = LayoutOptions.FillAndExpand,
            HorizontalOptions = LayoutOptions.FillAndExpand,
            BackgroundColor = Color.FromRgb(0.94, 0.94, 0.94),

            RowDefinitions =
            {
                new RowDefinition() { Height = new GridLength(0.333, GridUnitType.Star) },
                new RowDefinition() { Height = new GridLength(0.333, GridUnitType.Star) },
                new RowDefinition() { Height = new GridLength(0.333, GridUnitType.Star) }
            },

            ColumnDefinitions =
            {
                new ColumnDefinition() { Width = new GridLength(0.333, GridUnitType.Star) },
                new ColumnDefinition() { Width = new GridLength(0.333, GridUnitType.Star) },
                new ColumnDefinition() { Width = new GridLength(0.333, GridUnitType.Star) }
            }
        };

        serviceBoard.SetBinding(DashboardDesktop.ServiceIconsProperty, "Services");

这是我尝试创建我的 ObservableCollection 应该绑定到的 ServiceIcon 属性的自定义网格类

public class DashboardDesktop : Grid
{
    public static readonly BindableProperty ServiceIconsProperty =
         BindableProperty.Create
        (
        "ServiceIconsProperty",
        typeof(IList<ServiceModel>),
        typeof(DashboardDesktop),
        null,
        BindingMode.OneWay,
        (bindable, value) =>
        {
            return true;
        },
        (bindable, oldValue, newValue) =>
        {
            //do stuffs here
            //This is random stuff so I could add a breakpoint here
            int x = 10;
            var b = (IList<ServiceModel>)newValue;

            //Determine if an service have been removed or added
        });

    private IList<ServiceModel> Services { set; get; }


    public DashboardDesktop()
    {

    }
}

现在我尝试在 ServiceIconProperty 的“OnChanged”lambda 函数中放置一个断点,但即使我在 ViewModel 中的 ObservableCollection 中添加了很多元素,它也从未停止过

我做错了什么?

【问题讨论】:

    标签: c# mvvm xamarin xamarin.forms


    【解决方案1】:

    你做错了几件事。

    1. 您正在创建Binding,但没有为其提供绑定源 (有多种方法可以做到这一点)。
    2. BindableProperty.Create() 的 propertyName 参数不应包含“Property”后缀。
    3. 没有理由在您的 DashboardDesktop 类中包含“服务”集合。
    4. 您没有为 ServiceIcons 属性提供任何视觉效果。

    要解决第一个问题,您只需将serviceBoardBindingSource 设置为视图模型的实例使用SetBinding() 的不同重载,它允许您指定源对象。

    第四个也很重要 - 但也许您打算在评论 //Determine if an service have been removed or added 所在的属性回调中插入/删除可视子项?

    无论如何,我不确定我是否会首先采用这种整体方法。改为定义您自己的自定义模板化布局容器会更简洁(并且更符合 XAML 的精神)。本质上,从Layout&lt;View&gt; 继承并相应地添加基于网格的定位逻辑,并添加ItemsSourceItemTemplate。您应该能够查看内置的 ListView 类,以了解 Xamarin 如何在那里实现这些功能并从中借鉴。

    【讨论】:

      【解决方案2】:

      您正在绑定集合,而不是集合的内容。

      所以这个绑定只被调用一次(在它被创建的时候)并且再也不会被调用。

      在Services的setter中,你必须订阅你收到的ObservableCollection对象的改变事件。

      【讨论】:

      • 我不明白,我希望在调用 Services 时触发该事件。当我执行 Services = Something 时不要添加。我认为 ObservableCollection 内置了这种行为?
      • 向 ObservableCollection 添加项目时触发事件。但是您的绑定不订阅它。由于您对列表项有特定的展示,因此您必须手动完成。
      • 你能举个例子吗?我真的不明白你想告诉我什么,对不起。如何从 ObservableCollection 订阅 Item 添加事件?
      • 我也想知道如何订阅 ObservableCollection/List 项添加事件。
      猜你喜欢
      • 2018-10-21
      • 1970-01-01
      • 1970-01-01
      • 2020-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多