繁体   English   中英

Xamarin Forms ViewModel 绑定/多个绑定对象

[英]Xamarin Forms ViewModel Binding / Multiple Binding objects

Xamarin Forms 相对较新,并尝试使用 Realm,如果这是基本且易于解决的,请原谅我。 我的大脑目前正试图弄清楚这一点。

我有以下型号:

public class State : RealmObject
{
    [PrimaryKey]
    [MapTo("_id")]
    public ObjectId Id { get; set; } = ObjectId.GenerateNewId();
    public string StateShort { get; set; }
    public string StateName { get; set; }
}

public class SalesOrder : RealmObject
{
    [PrimaryKey]
    [MapTo("_id")]
    public ObjectId Id { get; set; } = ObjectId.GenerateNewId();
    public string ContactName { get; set; }
    public string ContactEmailAddress { get; set; }
    public string CompanyName { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public State State { get; set; }
    public string ZipCode { get; set; }
    public string County { get; set; }
}

我有一个用于设置新销售订单的内容页面,如下所示:
销售订单NewPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TestRealm.Views.SalesOrderNewPage">
    <ContentPage.Content>
        <ScrollView>
            <StackLayout Spacing="3" Padding="15">
                <Label Text="Contact Name" FontSize="Medium" />
                <Entry Text="{Binding ContactName, Mode=TwoWay}" FontSize="Medium" />
                <Label Text="Contact Email" FontSize="Medium" />
                <Editor Text="{Binding ContactEmailAddress, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
                <Label Text="Company Name" FontSize="Medium" />
                <Editor Text="{Binding CompanyName, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
                <Label Text="Address" FontSize="Medium" />
                <Editor Text="{Binding Address, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
                <Label Text="City" FontSize="Medium" />
                <Editor Text="{Binding City, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
                <Label Text="State" FontSize="Medium" />
                <Picker x:Name="StatePicker"
                        Title="--- select state ---"
                        ItemsSource="{Binding States}"
                        ItemDisplayBinding="{Binding StateShort}"
                        SelectedItem="{Binding SelectedState}" />
                <Label Text="Zip Code" FontSize="Medium" />
                <Editor Text="{Binding ZipCode, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
                <Label Text="County" FontSize="Medium" />
                <Editor Text="{Binding County, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
                <Label Text="Application" FontSize="Medium" />
                <Picker x:Name="ApplicationPicker"
                        Title="--- select application ---">
                    <Picker.ItemsSource>
                        <x:Array Type="{x:Type x:String}">
                            <x:String>Application 1</x:String>
                            <x:String>Application 2</x:String>
                        </x:Array>
                    </Picker.ItemsSource>
                </Picker>       
                <StackLayout Orientation="Horizontal">
                    <Button Text="Cancel" Command="{Binding CancelCommand}" HorizontalOptions="FillAndExpand"></Button>
                    <Button Text="Save" Command="{Binding SaveCommand}" HorizontalOptions="FillAndExpand"></Button>
                </StackLayout>
            </StackLayout>
        </ScrollView>
    </ContentPage.Content>
</ContentPage>

以及该 xaml 页面的代码隐藏 /.cs 文件
SalesOrderNewPage.xaml.cs

using MongoDB.Bson;
using System.Collections.Generic;
using TestRealm.Models;
using TestRealm.ViewModels;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace TestRealm.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class SalesOrderNewPage : ContentPage
    {
        public SalesOrder SalesOrder { get; set; }

        public List<State> AllStates { get; set; }
        public SalesOrderNewPage()
        {
            InitializeComponent();
            var states = new List<State>()
            {
                new State { Id = ObjectId.GenerateNewId(), StateShort = "NY", StateName = "New York" },
                new State { Id = ObjectId.GenerateNewId(), StateShort = "PA", StateName = "Pennsylvania" } ,
                new State { Id = ObjectId.GenerateNewId(), StateShort = "VT", StateName = "Vermont" }
            };

            BindingContext = new SalesOrderNewViewModel();
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
        }
    }
}

这是查看 Model 或页面
SalesOrderNewViewModel.cs

using MongoDB.Bson;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using TestRealm.Models;
using Xamarin.Forms;

namespace TestRealm.ViewModels
{
    public class SalesOrderNewViewModel : BaseViewModel
    {
        private string contactname;
        private string contactemailaddress;
        private string companyname;
        private string address;
        private string city;
        private string state;
        private string zipcode;
        private string county;
        private List<State> states;

        public ObservableCollection<State> States { get; set; }
        public SalesOrderNewViewModel()
        {
            States = new ObservableCollection<State>();
            SaveCommand = new Command(OnSave, ValidateSave);
            CancelCommand = new Command(OnCancel);
            this.PropertyChanged +=
                (_, __) => SaveCommand.ChangeCanExecute();
        }

        private bool ValidateSave()
        {
            return !String.IsNullOrWhiteSpace(contactname)
                && !String.IsNullOrWhiteSpace(contactemailaddress)
                && !String.IsNullOrWhiteSpace(companyname);
        }

        public string ContactName
        {
            get => contactname;
            set => SetProperty(ref contactname, value);
        }

        public string ContactEmailAddress
        {
            get => contactemailaddress;
            set => SetProperty(ref contactemailaddress, value);
        }

        public string CompanyName
        {
            get => companyname;
            set => SetProperty(ref companyname, value);
        }

        public string Address
        {
            get => address;
            set => SetProperty(ref address, value);
        }

        public string City
        {
            get => city;
            set => SetProperty(ref city, value);
        }

### ERROR HERE ###
cannot implicity convert type 'string' to 'TestRealm.Models.State'

        public State State
        {
            get => state;
            set => SetProperty(ref state, value);
        }

        public string ZipCode
        {
            get => zipcode;
            set => SetProperty(ref zipcode, value);
        }

        public string County
        {
            get => county;
            set => SetProperty(ref county, value);
        }


        public Command SaveCommand { get; }
        public Command CancelCommand { get; }

        private async void OnCancel()
        {
            // This will pop the current page off the navigation stack
            await Shell.Current.GoToAsync("..");
        }

        private async void OnSave()
        {
            SalesOrder salesOrder = new SalesOrder()
            {
                Id = ObjectId.GenerateNewId(),
                ContactName = ContactName,
                ContactEmailAddress = ContactEmailAddress,
                CompanyName = CompanyName,
                Address = Address,
                City = City,
                State = State,
                ZipCode = ZipCode,
                County = County
            };

            await DataStore.AddSalesOrderAsync(salesOrder);

            // This will pop the current page off the navigation stack
            await Shell.Current.GoToAsync("..");
        }
    }
}

而且,当然,这是我相信大多数人都在使用的 BaseViewModel.cs 文件 Xamarin Forms
BaseViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using TestRealm.Models;
using TestRealm.Services;
using Xamarin.Forms;

namespace TestRealm.ViewModels
{
    public class BaseViewModel : INotifyPropertyChanged
    {
        public IDataStore<SalesOrder> DataStore => DependencyService.Get<IDataStore<SalesOrder>>();

        bool isBusy = false;
        public bool IsBusy
        {
            get { return isBusy; }
            set { SetProperty(ref isBusy, value); }
        }

        string title = string.Empty;
        public string Title
        {
            get { return title; }
            set { SetProperty(ref title, value); }
        }


        protected bool SetProperty<T>(ref T backingStore, T value,
            [CallerMemberName] string propertyName = "",
            Action onChanged = null)
        {
            if (EqualityComparer<T>.Default.Equals(backingStore, value))
                return false;

            backingStore = value;
            onChanged?.Invoke();
            OnPropertyChanged(propertyName);
            return true;
        }

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var changed = PropertyChanged;
            if (changed == null)
                return;

            changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
}

因此,我在 State 上的SalesOrderNewViewModel.cs文件中出现错误,因为它不是字符串,但实际上是 ZA559B87068921EEC05086CE5485 中 State 的属性。 我根本不知道如何处理这个问题,也没有找到任何指导。 我正在尝试使用选择器从 State Model 中提取 id 属性,并在选择器中显示 StateName 或 StateShort。 但是,它应该为 SalesOrder model 中的 State 设置 id 属性。

抱歉太无知了。
任何帮助表示赞赏,谢谢。

因此,我认为您的代码在多个级别上存在一些混淆。

捆绑

预计您的代码中会出现错误,因为您正在尝试使用作为Stringstate变量作为支持字段,但是您的属性State的类型是State 因此,您的支持字段应该与属性本身相同

private State state;

这将消除错误。 我注意到的另一件事是,您在SalesOrderNewPage.xaml.cs中定义了SalesOrderAllStates ,但您没有使用它们(如果您想遵循“纯”MVVM 架构,可能不应该使用它们)。

选择器

选择器是一个控件,用于显示显示项目列表,用户可以 select。 这意味着您为选择器绑定到ItemSource的属性应该是List ,而在您的情况下,您只有一个值。 如果您的 SalesOrder 可以有多个状态,那么修改您的 SalesOrder model 以具有列表属性可能会很方便:

public IList<State> States { get; set; }

无论如何,我不能 100% 确定您要向用户展示什么,所以我的回答不能更准确,但是在这个其他答案中,您可以找到一个如何使用 Picker 来展示列表中的元素。 我希望其他答案能推动您朝着正确的方向前进:)

Realm

作为旁注,这不是 realm 的问题,而是 Xamarin Forms 和绑定的问题。 不过,我可以在您的代码中看到您正在使用类似于存储库模式的东西,也就是说,您不是直接在 ViewModel 中访问realm而是在依赖项中“隐藏”您的数据访问。 Realm 不鼓励这种方法,因为:

  1. 您失去了使用 Realm 的一些优势,即所有对象都是实时且自动更新的。
  2. 它使线程的生活变得复杂,因为后台线程上的领域需要与主线程上的 realm 区别对待。 您可以查看其他答案以获取更多详细信息。

这个虚拟 Realm Meetup的第二部分中,还有关于如何处理线程以及为什么存储库模式不是一个好主意的更详细说明。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM