考虑以下模型:
public class Person
{
public string FirstName { get; set; }
}
绑定到FirstName
财产,任何更新名字就不会有属性更改的通知。实现这一点的唯一方法是如果您的模型实现了INotifyPropertyChanged
。
也就是说,直接绑定到模型可能是一个很好的策略。作为一个常见示例,如果您有ListView
,则通常可以安全地绑定到ObservableCollection<SomeModel>
。如果你正在使用一个相对较小的数据集,并且可以承担重新加载数据源的开销,那么你一直都很安全。
现在就如何绑定到一个属性,因为:
public class ViewAViewModel : BindableBase
{
private Person _myPerson;
public Person MyPerson
{
get { return _myPerson; }
set { SetProperty(ref _myPerson, value); }
}
}
XAML标记看起来是这样的:
<Label Text="{Binding MyPerson.FirstName}" />
UPDATE:
如文献你的更新问题,是的,你可以实现这样的INotifyPropertyChanged
。记住它已经做了你BindableBase
所以给你的例子,你可以简单地从BindableBase
继承...另一个很好的选择是,如果你使用MvvmHelpers从詹姆斯Montemagno你可以用他ObservableObject
您的模型和BaseViewModel
为您的ViewModels,让你的属性如Title,SubTitle,Icon,IsBusy,IsNotBusy。
这样做,当然这一点的好处是,你现在必须直接绑定到模型的能力。一查看很少知道只是一个模型考虑以下因素:
角色模型
public class Person : BindableBase
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set { SetProperty(ref _firstName, value); }
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set { SetProperty(ref _lastName, value); }
}
private DateTime _dob;
public DateTime DOB
{
get { return _dob; }
set { SetProperty(ref _dob, value); }
}
}
用户配置文件视图模型
public class UserProfileViewModel : BindableBase, INavigationAware
{
INavigationService _navigationService { get; }
IPageDialogService _pageDialogService { get; }
public UserProfileViewModel(INavigationService navigationService, IPageDialogService pageDialogService)
{
_navigationService = navigationService;
_pageDialogService = pageDialogService;
DoFooCommand = new DelegateCommand(() => _pageDialogService.DisplayAlertAsync("Alert", "Foo", "Ok"));
}
private bool shouldSave = false;
private string _title;
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
private Person _user;
public Person User
{
get { return _user; }
set { SetProperty(ref _user, value); }
}
public DelegateCommand DoFooCommand { get; }
public void OnNavigatingTo(NavigationParameters parameters)
{
Title = AppResources.UserProfilePageTitle;
User = parameters.GetValue<Person>("currentUser");
User.PropertyChanged += (sender, e) => shouldSave = true;
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
if(shouldSave)
{
// Do your persistence here.
}
}
public void OnNavigatedTo(NavigationParameters parameters)
{
User.DOB = new DateTime(2017, 1, 1);
}
}
用户个人资料查看
<ContentPage Title="{Binding Title}">
<StackLayout>
<Label Text="First Name" />
<Entry Text="{Binding User.FirstName}" />
<Label Text="Last Name" />
<Entry Text="{Binding User.LastName}" />
<Label Text="{Binding User.DOB}" />
<Button Text="Do Foo" Command="{Binding DoFooCommand}" />
</StackLayout>
</ContentPage>
鉴于此代码应该有几件事情值得一提:
1)我们的视图模型包含什么都没有做什么那么我们的模型像命令,或类似的标题性质的各种事情。它也有可能消费的各种服务,如INavigationService
或IPageDialogService
2)其次,我们可能要限制哪些属性的用户可以编辑和视图模型可以编辑。 3)如果我们的模型实现了INotifyPropertyChanged
,我们可以附加一个事件处理程序,让我们知道我们的模型在设置后发生了变化,因此我们可以保留这些更改。
4)它使XAML更具可读性了解我们的意图。我们不绑定一些名为FirstName的魔术属性。我们真的绑定了我们的Person模型的FirstName属性。
我已更新我的问题以添加INPC的实现。通过在已经实现INPC的视图模型中拥有属性,我获得了什么? – Ken
它变得更清晰。感谢你和我一起在那里。在你的视图模型中,你有一个带有后台字段的用户属性。那完成了什么?为什么不只是有一个自动实施的财产? – Ken
从技术上讲,它不应该需要它,因为模型实现了'INotifyPropertyChanged',但是我倾向于按照约定来做所有事情,除了一个'ObservableCollection'或其他明确命名为'Observable'的自定义Observable Type。它确保更好的代码可读性。 –