问题
I am having some problems understanding xaml with mvvm. Sometimes works but others doesn't.
ViewModel (implements INotifyPropertyChanged):
private Class1 firstClass;
public Class1 FirstClass{
get{return firstClass;}
set{firstClass = value; OnPropertyChanged();}
}
private string name;
public string Name{
get{return name;}
set{name = value; OnPropertyChanged();}
}
private string address;
public string Address{
get{return address;}
set{address = value; OnPropertyChanged();}
}
View:
private ViewModel vm;
In the View constructor:
vm = new ViewModel(id);
BindingContext = vm;
OnAppearing (async):
base.OnAppearing();
await vm.LoadDataAsync();
lAddress.SetBinding(Label.TextProperty, new Binding("Address");
If I set the BindingContext in xaml and remove it from the constructor, it does not work.
If I set the Binding on the Address label in xaml and remove it from the code behind, it does not work.
If I try to use Name as the Title of the page, it does not work.
In any of these cases I am not getting any error like 'Binding: property not found on BindingContext' so I understand that they are being found but maybe they are empty.
If I modify a property from Class1, it does not appear on the page. Can I assume that the reason is that Class does not implement INotifyPropertyChanged?
Is it better or advisable to LoadData in VM constructor (Task.Run) or on Page.OnAppearing(await vm.LoadData())?
Could anybody provide a bit of guidance?
EDIT:
XAML code (sorry, could not add the code itself)
回答1:
This is getting to a fair bit of debugging (and a reason why one question per post might make more sense); but here goes:
Your view model has a constructor that takes a parameter. If you construct in XAML it will use the default. Basically, the two pieces of code you are comparing are not equivalent. If you need the parameter keep it like you have it.
You'll need to debug this one; ensure the bound property isn't actually empty for starters.
No idea; same as the address you probably need to debug it.
Your interpretation of this is correct; I would be checking that my data is loaded properly.
Yes. Your current code will only update if
FirstClass
is reassigned. To catch assignment of properties within that objectClass1
will need INPC (perhaps this explains 2 and/or 3)Not sure it really matters.
回答2:
If I set the BindingContext in xaml and remove it from the constructor, it does not work.
How do you set it in XAML
? You have to provide an int
parameter to the constructor. So most probably it will make sense to set the BindingContext
of the page in C#:
class MyPage
{
ViewModel vm;
public MyPage(int id)
{
InitializeComponent();
vm = new ViewModel(id);
BindingContext = vm;
}
}
Please note that you introduce a tight coupling here, since your Page
is aware of the ViewModel
concrete type.
If I set the Binding on the Address label in xaml and remove it from the code behind, it does not work.
Here is how a Label
with binding should look like in XAML
:
<Label Text="{Binding Address}" />
If I try to use Name as the Title of the page, it does not work.
Here is how to create a binding to a page title:
ContentPage.SetBinding(Page.TitleProperty, nameof(Class1.Name));
Please note that it should be called after you set the BindingContext
of the page.
In any of these cases I am not getting any error like 'Binding: property not found on BindingContext' so I understand that they are being found but maybe they are empty.
Try to put a break point after vm.LoadDataAsync()
and check the content of the ViewModel
.
If I modify a property from Class1, it does not appear on the page. Can I assume that the reason is that Class does not implement INotifyPropertyChanged?
The more I follow your questions, the more it seems like an implementation problem of INotifyPtopertyChanged
can you share the relevant code?
Is it better or advisable to LoadData in VM constructor (Task.Run) or on Page.OnAppearing(await vm.LoadData())?
Constructor should be as simple as possible, never user constructors to execute code that may fail as a rule of thumb. So it is better to introduce an interface that your ViewModel
will implement and which should have to methods OnAppearing()
& OnDisappearing()
, then your page will be not aware of the ViewModel
concrete type. I guess the rest should be clear.
回答3:
I think that the problem is here:
OnAppearing (async):
base.OnAppearing();
lAddress.SetBinding(Label.TextProperty, new Binding("Address");
await vm.LoadDataAsync();
You must set the binding before the method's call.
来源:https://stackoverflow.com/questions/50275668/problems-with-bindings-in-xamarin-forms-mvvm