【发布时间】:2020-11-19 19:46:03
【问题描述】:
我有一个简单的 Xamarin.Forms 项目,带有 Picker。
我的视图绑定到一个继承自 INotifyPropertyChanged 的视图模型。
我定义了一个ObservableCollection,比如:
public ObservableCollection<User> UserList { get; set; }
由 HTTP 客户端 Get 方法填充:
UserList = JsonConvert.DeserializeObject<ObservableCollection<User>>(s);
我已经验证UserList 填充了预期的数据。
这是我的选择器:
<Picker Title="User"
Grid.Row="0"
Grid.Column="0"
ItemsSource="{Binding UserList}"
ItemDisplayBinding="{Binding UserName}"
SelectedItem="{Binding UserSelectedItem}"/>
这是我的SelectedItem 绑定属性:
public User UserSelectedItem { get; set; }
我没有使用OnPropertyChanged 的UserSelectedItem。
问题:
我的Picker 中没有任何值,即使我已经验证UserList 中确实包含预期的数据。
编辑
我修改了我的ObservableCollection 以使用 OnPropertyChanged:
private ObservableCollection<User> _userList;
public ObservableCollection<User> UserList
{
get
{
return _userList;
}
set
{
_userList = value;
OnPropertyChanged(nameof(UserList));
}
}
但是数据仍然没有进入选择器...
编辑 2 我仍然无法弄清楚这一点。 这是我的 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="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>
这是我的 XAML 代码:
public partial class JoinCrew : ContentPage
{
private JoinCrewViewModel viewModel { get; set; }
public JoinCrew()
{
InitializeComponent();
viewModel = new JoinCrewViewModel();
BindingContext = viewModel;
}
}
这是我的视图模型:
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;
}
}
我可以像以前一样确认我有数据通过 Http 客户端返回到我的 IList
我不明白为什么选择器没有被填满。这似乎应该很容易做到。
【问题讨论】:
-
UserList 设置器是否调用 PropertyChanged?如果不是,那么在分配数据时 UI 将不会更新。您可以尝试通过在获取数据时手动设置 ItemsSource 而不是使用绑定来验证这一点。
-
嗨 Jason,我曾假设 ObservableCollection 是双向绑定。我理解错了吗?
-
OC 仅在添加/删除/清除项目时更新。因为你在获取数据的时候是在创建一个OC的新实例,所以它需要通过PropertyChanged告诉UI集合对象本身已经改变了
-
嗨,Jason,我在帖子中添加了一些代码。我修改了 OC 以使用 OnPropertyChanged,但仍然没有得到任何数据。
-
您是否尝试手动设置 ItemsSource?
标签: c# xaml xamarin.forms inotifypropertychanged