绑定到模型以进行属性更改

时间:2017-03-09 19:49:57

标签: mvvm data-binding prism

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

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;
}

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

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

@RequestMapping(value="/test/{firstNameIds}", method=RequestMethod.GET)
@ResponseBody
public String test(@PathVariable List<Integer> firstNameIds) {
    //Example: pring your params
    for(Integer param : firstNameIds) {
        System.out.println("id: " + param);
    }
    return "Dummy";
}

2 个答案:

答案 0 :(得分:4)

鉴于以下模型:

public class Person
{
   public string FirstName { get; set; }
}

绑定到FirstName属性,对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}" />

<强>更新

如您更新的问题中所述,是的,您可以像这样实施INotifyPropertyChanged。请记住,BindableBase已经为您完成了,所以根据您的示例,您可以继承BindableBase ...另一个不错的选择是,如果您使用James Montemagno的MvvmHelpers,您可以使用他的ObservableObject 1}}在您的模型上,BaseViewModel用于您的ViewModel,它为您提供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 ); }
    }
}

用户个人资料ViewModel

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)我们的ViewModel包含各种各样的东西,这些东西与我们的模型(如命令)或Title等属性无关。它也可能会消耗INavigationServiceIPageDialogService

等各种服务

2)其次,我们可能想要限制用户可以编辑哪些属性,ViewModel可以编辑。

3)如果我们的模型实现INotifyPropertyChanged,我们可以附加一个事件处理程序,让我们知道我们的模型在设置之后发生了变化,这样我们就可以保留这些变化。

4)它使XAML对我们的意图更具可读性。我们没有绑定一些名为FirstName的魔法属性。我们真的绑定到Person模型的FirstName属性。

答案 1 :(得分:0)

  

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

要绑定到模型的属性,您必须将数据绑定到公开模型及其属性的属性,即,如果您使用属性“Person”公开了模型 并且想要绑定到person的Name属性,你不需要绑定到'Person.Name'。

  

这是否会通知财产变更?

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

SetProperty方法将负责通知属性更改。