【问题标题】:Xamarin forms read local json file and display in pickerXamarin 表单读取本地 json 文件并显示在选取器中
【发布时间】:2020-07-07 17:35:45
【问题描述】:

我正在尝试将联系人的 json 文件解析为列表,并在显示联系人姓名的页面上的选择器中将该列表显示给用户。

我的项目根目录中有一个名为“contacts.json”的 json 文件,它的构建操作设置为嵌入式资源。

我的 contacts.json 文件

{
  "contacts": [
    {
      "name": "JOE",
      "email": "name@handle",
      "phoneNumber": "123-456-7890"
    },
    {
      "name": "JYM",
      "email": "name@handle",
      "phoneNumber": "123-456-7890"
    }
  ]
}

我的联系方式:

    public partial class RootObject
    {
        [JsonProperty("contacts")]
        public List<Contact> Contacts { get; set; }
    }

    public partial class Contact
    {
        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("email")]
        public string Email { get; set; }

        [JsonProperty("phoneNumber")]
        public string PhoneNumber { get; set; }
    }

我实现 json 解析器的页面视图模型

    public partial class Page10 : BaseViewModel
    {
        private List<Contact> _contacts;
        public List<InternalContact> contacts
        {
            get { return _contacts; }
            set
            {
                _contacts = value;
                OnPropertyChanged("contacts");
            }
        }

        public Page10()
        {
            Title = "Spill Info";
            contacts = GetJsonData();
        }

        private List<Contact> GetJsonData()
        {
            string jsonFileName = "contacts.json";
            RootObject ObjContactList = new RootObject();


            var assembly = typeof(Page10).GetTypeInfo().Assembly;
            Stream stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{jsonFileName}");
            using (var reader = new System.IO.StreamReader(stream))
            {
                var jsonString = reader.ReadToEnd();

                //Converting JSON Array Objects into generic list    
                ObjContactList = JsonConvert.DeserializeObject<RootObject>(jsonString);
            }   
            return ObjContactList.Contacts;
        }
    }

我的基础视图模型

public class BaseViewModel : INotifyPropertyChanged
    {
        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
    }

我的 page.xaml.cs

public partial class Page10 : ContentPage
    {
        public Page10()
        {
            InitializeComponent();
            this.BindingContext = new contactviewmodel();
        }
    }

我的页面 xaml

<ContentPage.Content>
        <StackLayout>
            <Picker Title="contacts" ItemsSource="{Binding contacts}" ItemDisplayBinding="{Binding Name}"/>    
        </StackLayout>
    </ContentPage.Content>

在尝试上述操作后,我在选择时得到一个空选择器,但我希望在选择器中看到 JOE 和 JYM。

编辑 1: 我设法让它们显示在一个列表中,所以我试图从那里将它们放入选择器,但我只得到我的对象类型而不是名称的列表在选择器中。更新代码以反映更改。 image of phone w/ contact list view and picker(还不能嵌入图片,没有足够的代表)。

edit2:修改代码以显示@Cherry Bu-MSFT 的实现

【问题讨论】:

  • myContactList 必须是公共属性 - 即,有一个 get;

标签: c# json xamarin.forms data-binding picker


【解决方案1】:

根据你的描述,我做了一个样品,你可以看看:

public partial class Page10 : ContentPage, INotifyPropertyChanged
{
    private List<Contact> _contacts;
    public List<Contact> contacts
    {
        get { return _contacts; }
        set
        {
            _contacts = value;
            RaisePropertyChanged("contacts");

        }
    }

    public Page10()
    {
        InitializeComponent();


        contacts = GetJsonData();


        this.BindingContext = this;
    }

   private List<Contact> GetJsonData()
    {
        string jsonFileName = "contacts.json";
        ContactList ObjContactList = new ContactList();


        var assembly = typeof(Page10).GetTypeInfo().Assembly;
        Stream stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{jsonFileName}");
        using (var reader = new System.IO.StreamReader(stream))
        {
            var jsonString = reader.ReadToEnd();

            //Converting JSON Array Objects into generic list    
            ObjContactList = JsonConvert.DeserializeObject<ContactList>(jsonString);
        }

        return ObjContactList.contacts;
    }


    public event PropertyChangedEventHandler PropertyChanged;      
    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public partial class ContactList
{
    [JsonProperty("contacts")]
    public List<Contact> contacts { get; set; }
}

public partial class Contact
{
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("email")]
    public string Email { get; set; }

    [JsonProperty("phoneNumber")]
    public string PhoneNumber { get; set; }
}

  <StackLayout>
        <ListView x:Name="MyListView" ItemsSource="{Binding contacts}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextCell Detail="{Binding Email}" Text="{Binding Name}" />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

        <Picker
            x:Name="MyPicker"
            ItemDisplayBinding="{Binding Name}"
            ItemsSource="{Binding contacts}" />
    </StackLayout>

请不要忘记实现 INotifyPropertychanged 接口来更新 nofity 数据。

更新:

如果你想使用mvvm获取本地Json文件并在ListView中显示数据,请看下面的代码,我使用的是mvvm模式。

 public partial class Page10 : ContentPage
{
    public Page10()
    {
        InitializeComponent();

        this.BindingContext = new contactviewmodel();
    }   

}

public class contactviewmodel:ViewModelBase
{
    private List<Contact> _contacts;
    public List<Contact> contacts
    {
        get { return _contacts; }
        set
        {
            _contacts = value;
            RaisePropertyChanged("contacts");

        }
    }

    public contactviewmodel()
    {
        contacts = GetJsonData();
    }
    private List<Contact> GetJsonData()
    {
        string jsonFileName = "contacts.json";
        ContactList ObjContactList = new ContactList();


        var assembly = typeof(Page10).GetTypeInfo().Assembly;
        Stream stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{jsonFileName}");
        using (var reader = new System.IO.StreamReader(stream))
        {
            var jsonString = reader.ReadToEnd();

            //Converting JSON Array Objects into generic list    
            ObjContactList = JsonConvert.DeserializeObject<ContactList>(jsonString);
        }
        //Binding listview with json string     
        return ObjContactList.contacts;
    }

}

ViewModelBase 是实现 INotifyPropertyChanged 的​​类:

 public class ViewModelBase : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;      
    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

再次更新:

您可以使用以下代码获取Json文件。

 private void LoadData()
    {
        var assembly = typeof(Page10).GetTypeInfo().Assembly;
        foreach (var res in assembly.GetManifestResourceNames())
        {
            if (res.Contains("contacts1.json"))
            {
                Stream stream = assembly.GetManifestResourceStream(res);

                using (var reader = new StreamReader(stream))
                {
                    string data = "";
                    while ((data = reader.ReadLine()) != null)
                    {

                    }
                }
            }
        }
    }

【讨论】:

  • 感谢您的回复。也许我对 MVVM 的理解是错误的,但您来自 public partial class Page10 的大部分代码不应该在 Page10ViewModel.cs 文件中而不是 Page10.xaml.cs 文件中吗?视图模型是将用户界面链接到您的数据对吗?
  • @tbarlett17 如果你想用MVVM模式做你的项目,请拿我更新的代码。我之前的代码不是严格按照mvvm模式写的。
  • @tbartleet17 如果我的回复对您有帮助,请不要忘记将我的回复标记为答案,谢谢。
  • 感谢您的回复。我已经实现了你在这里的功能,但是当我点击我的选择器时,里面没有任何选项,我不知道为什么。我已经更新了原始帖子中的代码,您介意看看我是否遗漏了什么吗?
  • 请忽略最后一条评论。我从使用 List 更改为 ObservableCollection 并且它现在似乎正在工作。尽管考虑了反序列化器的流,但我确实还有另一个问题。如果我想将项目根目录中的 json 文件组织到项目中的文件夹中,我该怎么做?而不是 myproject/contacts.json 我可以把它放在名为 AppData 的文件夹中。 myproject/AppData/contacts.json
猜你喜欢
  • 2017-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-07
相关资源
最近更新 更多