INotifyPropertyChanged Xamarin字符串值刚刚消失 [英] INotifyPropertyChanged Xamarin string value just disappears
问题描述
我有一个Xamarin.Forms项目,其中的ListView装有ObservableCollection。 ObservableCollection中每个项目的类(对象)实现INotifyPropertyChanged。 Color属性可以在用户界面中很好地切换,但是字符串属性会消失并且永远不会返回。
I have a Xamarin.Forms project with a ListView populated with an ObservableCollection. The class (object) that is each item in the ObservableCollection implements INotifyPropertyChanged. A Color property toggles fine in the UI but a string property disappears and never returns.
我从Web服务获取了初始值,但是只是对它进行了完全静态的更改值,用于调试,但仍然无法弄清。
I get the initial values from a webservice but then just do a completely static change of the values, for debugging and I still can't figure it out.
在ContentPage类的顶部,我有以下内容:
At the top of the my ContentPage class I have this:
public ObservableCollection<GroceryItem> oc;
在Web服务返回数据后,我将数据放入ObservableCollection中,并使其成为ItemsSource用于列表视图。像这样:
After my webservice has returned with the data I put the data in the ObservableCollection and make that, the ItemsSource for the listview. Like this:
lvGroceries.ItemsSource = oc;
所有功能都很好。
XAML
<ListView x:Name="lvGroceries" ItemTapped="GroceryPdsItemTapped" >
<ListView.ItemTemplate >
<DataTemplate>
<ViewCell>
<AbsoluteLayout VerticalOptions="Fill">
<Label Text="{Binding GroceryName}" AbsoluteLayout.LayoutBounds="0,0,200,40" ></Label>
<Label Text="{Binding strHomeLoc}" AbsoluteLayout.LayoutBounds="200,0,100,40" ></Label>
<Label Text="{Binding isNeeded}" AbsoluteLayout.LayoutBounds="300,0,50,40" ></Label>
<Label Text="someText" BackgroundColor="{Binding myBackgroundColor}" AbsoluteLayout.LayoutBounds="350,0,50,40" ></Label>
</AbsoluteLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
类-GroceryItem
The class - GroceryItem
public class GroceryItem : INotifyPropertyChanged
{
public GroceryItem() { }
public event PropertyChangedEventHandler PropertyChanged;
private string privateIsNeeded;
public string isNeeded
{
get { return privateIsNeeded; }
set
{
privateIsNeeded = value;
OnPropertyChanged();
}
}
private Color theColor;
public Color myBackgroundColor
{
get { return theColor; }
set
{
theColor = value;
OnPropertyChanged();
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
点击处理程序。我从ObservableCollection中获取一个项目并更改了两个属性。
The click handler. I grab an item from the ObservableCollection and change the two properties.
public void GroceryPdsItemTapped(object obj, ItemTappedEventArgs e)
{
if (e.Item == null)
{
return;
}
var g = ((GroceryItem)e.Item);
foreach (var gr in oc)
{
if (gr.GroceryId == "27769")
{ // the UI changes because the myBackgroundColor property in the GroceryItem class is watching for a value change
gr.myBackgroundColor = (gr.myBackgroundColor == Color.Yellow) ? Color.Blue : Color.Yellow;
gr.isNeeded = (gr.isNeeded == "true" || gr.isNeeded == "blah" || gr.isNeeded == "false") ? "notblah" : "blah";
}
}
}
颜色在用户界面,但isNeeded字符串值在第一次点击时就消失了,再也不会出现
The Color toggles fine in the UI but the isNeeded string value disappears on the first tap and never re-appears
想法?
推荐答案
此处有几个问题。首先,您需要在更改后,使 ObservableCollection
运行 OnPropertyChanged()
:
A couple issues here. First is that you need to make your ObservableCollection
run OnPropertyChanged()
when it has been changed like so:
private ObservableCollection<GroceryItem> _oc;
public ObservableCollection<GroceryItem> oc {
get { return _oc ?? (_oc = new ObservableCollection<GroceryItem>()); }
set {
if(_oc != value) {
_oc = value;
OnPropertyChanged();
}
}
}
现在您应该真正拥有所有这在ViewModel中,但是由于您没有这样做,您需要在代码中将 ContentPage
设置为 BindingContext
-像这样:
Now you should really have all of this in a ViewModel but since you do not, you need to set your ContentPage
as the BindingContext
from within your code-behind like this:
public partial class MyGroceryPage : ContentPage {
public MyGroceryPage() { BindingContext = this; }
}
您还需要绑定 ObservableCollection
到您的 ListView.ItemSource
而不是分配它。看起来像这样:
You also need to be binding your ObservableCollection
to your ListView.ItemSource
instead of assigning it. That looks like this:
<ListView ItemSource="{Binding oc}"/>
如果执行上述操作,然后进入代码后面并执行 lvGroceries.ItemsSource = oc;
会覆盖您在XAML中所做的绑定,因此请勿这样做。相反,当您从Web服务获取数据时,只需将其分配给现有的 ObservableCollection
:
If you do the above and then you go into your code behind and execute lvGroceries.ItemsSource = oc;
then that would overwrite the binding that you did in your XAML, so do not do that. Instead, when you get data from your web service, you would just assign it to your existing ObservableCollection
:
public async Task GetGroceryData() {
List<GroceryItem> myData = await GroceryService.GetGroceriesAsync();
oc = new ObservableCollection<GroceryItem>(myData);
}
请先尝试所有操作,如果您的商品仍未更新,则可能需要尝试从 ObservableCollection
中删除它们,更改属性,然后将它们重新添加到以下内容中:
Try all of that first and if your items are still not updating you might want to try removing them from your ObservableCollection
, changing the properties, then adding them back in:
public void GroceryPdsItemTapped(object obj, ItemTappedEventArgs e) {
if (e.Item == null) { return; }
var g = ((GroceryItem)e.Item);
foreach (var gr in oc.ToList()) {
if (gr.GroceryId == "27769") { // the UI changes because the myBackgroundColor property in the GroceryItem class is watching for a value change
oc.Remove(gr);
gr.myBackgroundColor = (gr.myBackgroundColor == Color.Yellow) ? Color.Blue : Color.Yellow;
gr.isNeeded = (gr.isNeeded == "true" || gr.isNeeded == "blah" || gr.isNeeded == "false") ? "notblah" : "blah";
oc.Add(gr);
}
}
}
这篇关于INotifyPropertyChanged Xamarin字符串值刚刚消失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!