2017-03-09 205 views
0

在另一篇文章(Prism BindableBase.SetProperty())上,@ brian-lagunas说他更喜欢将Model作为属性公开,并将View绑定到模型属性。他给出了以下示例代码:绑定到属性更改模型

public class MyViewModel : BindableBase 
{ 
    private Person _myPerson; 
    public Person Person 
    { 
     get { return _myPerson; } 
     set { SetProperty(ref _myPerson, value); } 
    } 
} 

但是,我不确定如何绑定到属性。这是否通知财产更改?

更新: 这是我如何在模型上实现INPC?如果是这样,我已经获得了什么,我不会通过将属性放在已支持INPC的视图模型中?

public class Person : INotifyPropertyChanged 
{ 
    private string _FirstName; 
    private string _LastName; 
    public string FirstName { get { return _FirstName; } set => SetProperty(ref _FirstName, value); } 
    public string LastName { get { return _LastName; } set => SetProperty(ref _LastName, value); } 
    private void SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null) 
    { 
     if (!Equals(storage,value)) 
     { 
      storage = value; 
      OnPropertyChanged(propertyName); 
     } 
    } 
    private void OnPropertyChanged(string propertyName) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
} 

回答

2

考虑以下模型:

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)我们的视图模型包含什么都没有做什么那么我们的模型像命令,或类似的标题性质的各种事情。它也有可能消费的各种服务,如INavigationServiceIPageDialogService

2)其次,我们可能要限制哪些属性的用户可以编辑和视图模型可以编辑。 3)如果我们的模型实现了INotifyPropertyChanged,我们可以附加一个事件处理程序,让我们知道我们的模型在设置后发生了变化,因此我们可以保留这些更改。

4)它使XAML更具可读性了解我们的意图。我们不绑定一些名为FirstName的魔术属性。我们真的绑定了我们的Person模型的FirstName属性。

+0

我已更新我的问题以添加INPC的实现。通过在已经实现INPC的视图模型中拥有属性,我获得了什么? – Ken

+0

它变得更清晰。感谢你和我一起在那里。在你的视图模型中,你有一个带有后台字段的用户属性。那完成了什么?为什么不只是有一个自动实施的财产? – Ken

+0

从技术上讲,它不应该需要它,因为模型实现了'INotifyPropertyChanged',但是我倾向于按照约定来做所有事情,除了一个'ObservableCollection'或其他明确命名为'Observable'的自定义Observable Type。它确保更好的代码可读性。 –

0

我不确定我是如何绑定到属性。

要绑定到模型的属性,你必须将数据绑定到属性暴露模型及其财产,也就是说,如果你已经暴露的财产“人” 你的模型,并要绑定到的人的名称属性, '不需要绑定'Person.Name'。

这是否通知财产变化?

https://msdn.microsoft.com/en-us/library/dn736263(v=pandp.50).aspx

SetProperty方法将通知属性更改的照顾。

+0

我明白的SetProperty将处理通知,但布赖恩的模式,而不是属性使用的SetProperty。如果财产发生变化,通知是否会被发送? – Ken

+0

是的,但它会是你的模型,谁就会发送属性更改通知,并作为后提到,你的模型需要实现通过曝光模式为属性INPC –

+0

那么我该怎么获得? SetProperty调用对模型有什么影响? – Ken