I have a simple Xamarin.Forms project with a Picker
.
My view is bound to a view model that inherits from INotifyPropertyChanged
.
I define an ObservableCollection
like:
public ObservableCollection<User> UserList { get; set; }
which gets filled by an HTTP client Get
method:
UserList = JsonConvert.DeserializeObject<ObservableCollection<User>>(s);
I have verified that UserList
gets filled with the expected data.
Here is my Picker:
<Picker Title="User"
Grid.Row="0"
Grid.Column="0"
ItemsSource="{Binding UserList}"
ItemDisplayBinding="{Binding UserName}"
SelectedItem="{Binding UserSelectedItem}"/>
This is my SelectedItem
binding property:
public User UserSelectedItem { get; set; }
I dont have UserSelectedItem
using OnPropertyChanged
.
The problem: I don't get any values in my Picker
even though I have verified that UserList
does have the expected data in it.
I modified my ObservableCollection
to use OnPropertyChanged:
private ObservableCollection<User> _userList;
public ObservableCollection<User> UserList
{
get
{
return _userList;
}
set
{
_userList = value;
OnPropertyChanged(nameof(UserList));
}
}
but the data is still not making it to the picker...
EDIT 2 I still cant figure this out. This is my XAML code:
<?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="PTSX.Views.JoinCrew">
<ContentPage.Content>
<StackLayout>
<Label Text="Join a Crew"
HorizontalOptions="CenterAndExpand" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="AUTO"/>
<RowDefinition Height="200"/>
<RowDefinition Height="200"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
<Picker x:Name ="UserPicker"
Title="User"
Grid.Row="0"
Grid.Column="0"
ItemsSource="{Binding UserList}"
ItemDisplayBinding="{Binding UserName}"
SelectedItem="{Binding UserSelectedItem}"/>
<Picker x:Name="CrewPicker"
Title="Crew"
Grid.Row="1"
Grid.Column="0"
ItemsSource="{Binding CrewList}"
ItemDisplayBinding="{Binding CrewName}"
SelectedItem="{Binding CrewSelectedItem}"/>
<Button x:Name="buttonJoinCrew"
Text="Join"
Grid.Row="2"
Grid.Column="0"
Command="{Binding JoinCrewCommand}"/>
<Button x:Name="buttonCreateCrew"
Text="Add Crew"
Grid.Row="3"
Grid.Column="0"
Command="{Binding AddCrewCommand}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
This is my XAML code behind:
public partial class JoinCrew : ContentPage
{
private JoinCrewViewModel viewModel { get; set; }
public JoinCrew()
{
InitializeComponent();
viewModel = new JoinCrewViewModel();
BindingContext = viewModel;
}
}
This is my view model:
public class JoinCrewViewModel : INotifyPropertyChanged
{
#region Fields
private string _crewName;
private string _crewId;
private string _userName;
private string _userId;
private IList<User> _userList;
private IList<DailyCrew> _crewList;
private User _userSelectedItem;
private DailyCrew _crewSelectedItem;
#endregion
#region Properties
public string CrewName
{
get
{
return _crewName;
}
set
{
_crewName = value;
OnPropertyChanged();
}
}
public string CrewId
{
get
{
return _crewId;
}
set
{
_crewId = value;
OnPropertyChanged();
}
}
public string UserName
{
get
{
return _userName;
}
set
{
_userName = value;
OnPropertyChanged();
}
}
public string UserId
{
get
{
return _userId;
}
set
{
_userId = value;
OnPropertyChanged();
}
}
public DailyCrew CrewSelectedItem
{
get => _crewSelectedItem;
set
{
_crewSelectedItem = value;
OnPropertyChanged();
}
}
public User UserSelectedItem
{
get => _userSelectedItem;
set
{
_userSelectedItem = value;
OnPropertyChanged();
}
}
public IList<DailyCrew> CrewList
{
get
{
return _crewList;
}
set
{
_crewList = value;
OnPropertyChanged();
}
}
public IList<User> UserList
{
get
{
return _userList;
}
set
{
_userList = value;
OnPropertyChanged();
}
}
#endregion
#region Events
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var propertyChanged = PropertyChanged;
propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Delegates
public Command JoinCrewCommand { get; }
public Command AddCrewCommand { get; }
#endregion
#region Contructor
public JoinCrewViewModel()
{
JoinCrewCommand = new Command(JoinCrewAction);
AddCrewCommand = new Command(AddCrewAction);
async Task FillUsersAsync();
}
private bool CanExecuteCommand(object commandParameter)
{
return true;
}
#endregion
#region Commands
private async void JoinCrewAction()
{
await JoinCrew();
}
#endregion
#region Private Methods
private async Task<IList<User>> FillUsersAsync()
{
IList<User> result = null;
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync($"https://xxx/api/mobile/getuserslist");
if (response.IsSuccessStatusCode)
{
string s = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<IList<User>>(s);
}
}
return result;
}
}
I can confirm like before that I have data being returned to my IList via the Http Client
I dont understand why the Picker is not getting filled. This seems like it should be pretty easy to do.
I have written a simple sample that is working perfectly on my side.
By Tapping the button the property that is bound to the Picker's ItemsSource gets loaded, and due to the OnPropertyChanged() call, the picker is notified that the collection changed and it loads the values correctly.
Please take a look at the sample and if you still have problems, share further details...
using System;
using Xamarin.Forms;
namespace PickerOC
{
public partial class MainPage : ContentPage
{
MainPageViewModel viewModel { get; set; }
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
viewModel = new MainPageViewModel();
BindingContext = viewModel;
}
private void Button_Clicked(object sender, EventArgs e)
{
viewModel.PickerData = new System.Collections.ObjectModel.ObservableCollection<UserX>()
{
new UserX("John L."), new UserX("Paul M."), new UserX("George H."), new UserX("Ringo S.")
};
}
}
}
<?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="PickerOC.MainPage">
<StackLayout>
<Picker ItemsSource="{Binding PickerData}"
ItemDisplayBinding="{Binding UserName}"/>
<Button Text="Load Picker Data!"
Clicked="Button_Clicked"/>
</StackLayout>
</ContentPage>
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace PickerOC
{
class MainPageViewModel : INotifyPropertyChanged
{
private ObservableCollection<UserX> _PickerData;
public ObservableCollection<UserX> PickerData
{
get => _PickerData;
set
{
_PickerData = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = "")
{
var propertyChanged = PropertyChanged;
propertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
public class UserX
{
public UserX(String name)
{
UserName = name;
}
public String UserName { get; set; }
}
}
I used your posted code and made it work on my side.
Note, i mocked the FillUsersAsync with a simple asynchronous function that awaits five seconds and then returns a collection of Users.
<ContentPage.Content>
<StackLayout>
<Label Text="Join a Crew"
HorizontalOptions="CenterAndExpand" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="AUTO"/>
<RowDefinition Height="200"/>
<RowDefinition Height="200"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
<Picker x:Name ="UserPicker"
Title="User"
Grid.Row="0"
Grid.Column="0"
ItemsSource="{Binding UserList}"
ItemDisplayBinding="{Binding UserName}"
SelectedItem="{Binding UserSelectedItem}"/>
<Picker x:Name="CrewPicker"
Title="Crew"
Grid.Row="1"
Grid.Column="0"
ItemsSource="{Binding CrewList}"
ItemDisplayBinding="{Binding CrewName}"
SelectedItem="{Binding CrewSelectedItem}"/>
<Button x:Name="buttonJoinCrew"
Text="Join"
Grid.Row="2"
Grid.Column="0"
Command="{Binding JoinCrewCommand}"/>
<Button x:Name="buttonCreateCrew"
Text="Add Crew"
Grid.Row="3"
Grid.Column="0"
Command="{Binding AddCrewCommand}"/>
</StackLayout>
</ContentPage.Content>
using Xamarin.Forms;
namespace PickerOC
{
public partial class MainPage : ContentPage
{
MainPageViewModel viewModel { get; set; }
public MainPage()
{
InitializeComponent();
viewModel = new MainPageViewModel();
BindingContext = viewModel;
}
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace PickerOC
{
class MainPageViewModel : INotifyPropertyChanged
{
#region Fields
private string _crewName;
private string _crewId;
private string _userName;
private string _userId;
private IList<User> _userList;
private IList<DailyCrew> _crewList;
private User _userSelectedItem;
private DailyCrew _crewSelectedItem;
#endregion
#region Properties
public string CrewName
{
get
{
return _crewName;
}
set
{
_crewName = value;
OnPropertyChanged();
}
}
public string CrewId
{
get
{
return _crewId;
}
set
{
_crewId = value;
OnPropertyChanged();
}
}
public string UserName
{
get
{
return _userName;
}
set
{
_userName = value;
OnPropertyChanged();
}
}
public string UserId
{
get
{
return _userId;
}
set
{
_userId = value;
OnPropertyChanged();
}
}
public DailyCrew CrewSelectedItem
{
get => _crewSelectedItem;
set
{
_crewSelectedItem = value;
OnPropertyChanged();
}
}
public User UserSelectedItem
{
get => _userSelectedItem;
set
{
_userSelectedItem = value;
OnPropertyChanged();
}
}
public IList<DailyCrew> CrewList
{
get
{
return _crewList;
}
set
{
_crewList = value;
OnPropertyChanged();
}
}
public IList<User> UserList
{
get
{
return _userList;
}
set
{
_userList = value;
OnPropertyChanged();
}
}
#endregion
#region Events
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var propertyChanged = PropertyChanged;
propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Delegates
public Command JoinCrewCommand { get; }
public Command AddCrewCommand { get; }
#endregion
#region Contructor
public MainPageViewModel()
{
JoinCrewCommand = new Command(JoinCrewAction);
AddCrewCommand = new Command(AddCrewAction);
Task.Run(async () => UserList = await FillUsersAsync());
//async Task FillUsersAsync();
}
private bool CanExecuteCommand(object commandParameter)
{
return true;
}
#endregion
#region Commands
private async void AddCrewAction()
{
await Task.Delay(1000);
}
private async void JoinCrewAction()
{
await Task.Delay(1000);
}
#endregion
#region Private Methods
private async Task<IList<User>> FillUsersAsync()
{
IList<User> result = null;
//using (var client = new HttpClient())
//{
// HttpResponseMessage response = await client.GetAsync($"https://xxx/api/mobile/getuserslist");
// if (response.IsSuccessStatusCode)
// {
// string s = await response.Content.ReadAsStringAsync();
// result = JsonConvert.DeserializeObject<IList<User>>(s);
// }
//}
await Task.Delay(5000);
result = new List<User>()
{
new User() {UserName = "John L."},
new User() {UserName = "Paul M."},
};
return result;
}
#endregion
}
public class User
{
public string UserID { get; set; }
public string UserName { get; set; }
}
public class DailyCrew
{
public string CrewId { get; set; }
public string CrewName { get; set; }
}
}
I used your posted code and made it work on my side for user picker.
ViewModel.cs
public class JoinCrewViewModel : INotifyPropertyChanged
{
#region Fields
private ObservableCollection<User> _userList;
private User _userSelectedItem;
#endregion
#region Properties
public User UserSelectedItem
{
get => _userSelectedItem;
set
{
_userSelectedItem = value;
OnPropertyChanged();
}
}
public ObservableCollection<User> UserList
{
get
{
return _userList;
}
set
{
_userList = value;
OnPropertyChanged();
}
}
#endregion
#region Events
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var propertyChanged = PropertyChanged;
propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Contructor
public JoinCrewViewModel()
{
FillUsersAsync();
}
#endregion
private async Task<ObservableCollection<User>> FillUsersAsync()
{
_userList = new ObservableCollection<User>() {
new User()
{
UserName = "test",
UserId = "1"
},
new User()
{
UserName = "test1",
UserId = "2"
},
new User()
{
UserName = "test2",
UserId = "3"
},
new User()
{
UserName = "test3",
UserId = "4"
},
new User()
{
UserName = "test3",
UserId = "5"
}
};
_userSelectedItem = _userList[2];
return _userList;
}
}
public class User
{
public string UserName { get; set; }
public string UserId { get; set; }
}
Home.xaml
<StackLayout>
<Label Text="Join a Crew"
HorizontalOptions="CenterAndExpand" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="AUTO"/>
<RowDefinition Height="200"/>
<RowDefinition Height="200"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
<Picker x:Name ="UserPicker"
Title="User"
Grid.Row="0"
Grid.Column="0"
ItemsSource="{Binding UserList}"
ItemDisplayBinding="{Binding UserName}"
SelectedItem="{Binding UserSelectedItem}"/>
</StackLayout>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.