Xamarin Forms StackLayout不会重置/缓存。

huangapple go评论79阅读模式
英文:

Xamarin Form Stacklayout not resetting/Cached

问题

我们有一个类,其中包含一个名为'ItemJson'的属性,其类型为JSON文本,稍后将其转换为只读属性'Items'中的List<Class2>。现在我们使用这些Items将Stacklayout绑定到UI中。在按钮操作中,我们通过API将ItemJson保存到数据库,并将用户转到感谢页面。当用户返回时,他应该看到空白屏幕,为此我们设置了ViewModel,使用new关键字重新初始化我们的对象。但是它不会清除Stacklayout或Items变量,尽管ItemJson已被清空。这导致旧的Items仍然对用户可见。

所以我的类是(示例)

public class MyClass
{
    public string ItemJson { get; set; }
    public List<Class2> Items { get { return JsonConvert.DeserializeObject<List<Class2>>(ItemJson); } }
}

我的UI使用Items如下:

<Stacklayout Bindable="{Binding Obj.Items}" ... >
...DataTemplate等等...</Stacklayout>

我的ViewModel在UI的onAppearing函数中执行以下操作:

Obj = new MyClass();

但它不会清除Items属性。

编辑:
我忘了提到,我们通过Shell.Current.GoToAsync()导航,我甚至尝试使用Shell.Current.Navigation.PushAsync(),希望它不会重用上一个UI屏幕,从而变为空白。但它没有起作用。我们无法通过变量重新创建整个屏幕,因为在我们的流程中,我们必须在各个屏幕之间切换并返回。因此,如果重新创建或重新推送新对象,它会影响应用程序的流程。所以我们只需要在按下保存按钮时清除它。在保存按钮上,我尝试重新初始化这个对象,但它被一些内部编程缓存住了。

英文:

We have a class that is consist of property say 'ItemJson' as JSON text, which is later convert to List&lt;Class2&gt; in read only property called 'Items'.. now we use that Items to bind a Stacklayout in UI. On button action we save the ItemJson to database through API and move user to thanks screen.
When user came back he is suppose to see blank screen and for that we have Viewmodel set to reinitialize our object using new keyword. But it doesn't clear the Stacklayout or the Items variable although ItemJson is blank out. This results in old Items are still visible to user.

So my class is (Example)

Myclass { 
 public string ItemJson {get; set;} 
 public List&lt;Class2&gt; Items { get { return JsonConvert.DeserializeObject&lt;List&lt;Class2&gt;&gt;(ItemJson); } }
}

And my UI use Items as

&lt;Stacklayout Bindable=&quot;{Binding Obj.Items}&quot; ... &gt;
...DataTemplate etc..&lt;/Stacklayout&gt;

My ViewModel has function called onAppearing of UI, that did

Obj = new MyClass();

But it doesn't clear the Items property.

EDIT:
I forgot to mention, We navigate through Shell.Current.GoToAsync() and I even try to use Shell.Current.Navigation.PushAsync() in hope that it don't reuse last UI screen and hence come blank. But it didn't work. We cannot recreate full screen through variable as in our process we have to switch to various screen in between and come back. so If recreate or rePush new object it effect the flow of application. So we need just to clear in when we press save button. And on Save button I try to reinitialize this object but it is getting cached by some internal programming.

答案1

得分: 1

由于您尚未提供关于您的代码和具体问题的足够信息,我将根据我对您的问题的理解,尝试给出一个更通用的答案。

使属性可观察

您的类需要实现 INotifyPropertyChanged 接口,以便在 ItemJson 更改时通知 UI 关于 Items 的更改:

public class Myclass : INotifyPropertyChanged { 
    public event PropertyChangedEventHandler PropertyChanged;  

    private void OnPropertyChanged([CallerMemberName] string propertyName = "")  
    {  
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }   

    private string _itemJson;
    public string ItemJson
    {
        get => _itemJson;
        set
        {
            if(_itemJson == value) return;
            _itemJson = value;
            OnPropertyChanged();
            OnPropertyChanged(nameof(Items));
        }
    }

    public List<Class2> Items { get { return JsonConvert.DeserializeObject<List<Class2>>(ItemJson); } }
}

如果 Items 对象应该是空的,您需要将 ItemJson 设置为一个空的 JSON 数组,例如:

Obj.ItemJson = "[]";

这将清空列表,因为属性设置器调用了 OnPropertyChanged(nameof(Items));,然后通知 UI 更新到 Items 的绑定。

一些注意事项和改进建议

这不是一个理想的实现,但这是因为您的页面和视图模型的设置似乎设计得不太好(再次强调,这是基于很少的实际信息)。在属性的 getter 中反序列化 JSON 不是一个好的设计 - 如果解析器抛出异常怎么办?在更新 Items 属性为空时,不应该对 JSON 结构有依赖。

相反,您应该直接设置可观察的 Items 属性:

private List<Class2> _items;
public List<Class2> Items
{
    get => _items;
    set
    {
        if(_items == value) return;
        _items = value;
        OnPropertyChanged();
    }
}

然后,您可以在反序列化 JSON 后直接设置列表,例如:

public void UpdateData(string json)
{
    try
    {
        List<Class2> newData = JsonConvert.DeserializeObject<List<Class2>>(json);
        Items = newData;
    }
    catch(Exception ex)
    {
        Console.WriteLine(ex);
        Items = new List<Class2>();
    }
}

public void ClearData()
{
    Items = new List<Class2>();
}
英文:

Since you didn't share sufficient information (yet) about your code and the exact problem with it, I'll try to give a more generic answer based on how I understood your problem.

Make properties observable

Your class needs to implement the INotifyPropertyChanged interface in order to notify the UI about changes to the Items when the ItemJson changes:

public class Myclass : INotifyPropertyChanged { 
    public event PropertyChangedEventHandler PropertyChanged;  

    private void OnPropertyChanged([CallerMemberName] string propertyName = &quot;&quot;)  
    {  
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }   

    private string _itemJson;
    public string ItemJson
    {
        get =&gt; _itemJson;
        set
        {
            if(_itemJson == value) return;
            _itemJson = value;
            OnPropertyChanged();
            OnPropertyChanged(nameof(Items));
        }
    }

    public List&lt;Class2&gt; Items { get { return JsonConvert.DeserializeObject&lt;List&lt;Class2&gt;&gt;(ItemJson); } }
}

If the Items object is supposed to be empty, you need to set the ItemJson to an empty JSON array, e.g.:

Obj.ItemJson = &quot;[]&quot;;

This will clear the list, because OnPropertyChanged(nameof(Items)); is called by the property setter, which then notifies the UI to update the binding to Items.

Some notes and suggestions for improvement

This is not an ideal implementation, but that's because the setup of your Page and ViewModel doesn't seem to be well-designed (again, basing this on little actual information).

You shouldn't deserialize the JSON inside of a property getter - what if an exception is thrown by the parser? It's also not a good design to have a dependency on a JSON structure, because you shouldn't need to have an empty array or list in order to update the Items property to become empty.

Rather, you should directly set the Items property, which should also be observable:

private List&lt;Class2&gt; _items;
public List&lt;Class2&gt; Items
{
    get =&gt; _items;
    set
    {
        if(_items == value) return;
        _items = value;
        OnPropertyChanged();
    }
}

Then you can set the list directly after deserializing the JSON, e.g.:

public void UpdateData(string json)
{
    try
    {
        List&lt;Class2&gt; newData = JsonConvert.DeserializeObject&lt;List&lt;Class2&gt;&gt;(json);
        Items = newData;
    }
    catch(Exception ex)
    {
        Console.WriteLine(ex);
        Items = new List&lt;Class2&gt;();
    }
}

public void ClearData()
{
    Items = new List&lt;Class2&gt;();
}

huangapple
  • 本文由 发表于 2023年7月27日 18:05:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76778646.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定