c# - Listview 没有正确刷新项目视图
问题描述
我正在开发一个带有 xamarin 表单和 MVVM 模式的应用程序。我有一个包含三个按钮的列表视图页面,但始终只有 2 个可见按钮,并且当我按下按钮时会更改其中两个按钮的可见性。问题是,对于前十个项目,它按预期工作,按下按钮并消失并出现另一个,但是在第 10 个项目之后,当我按下按钮时它消失但另一个直到我滚动列表才出现查看项目在屏幕外的位置。当项目离开屏幕并重新出现在屏幕上时,按钮会出现。按钮的可见性被控制更改绑定到按钮的 IsVisible 属性的布尔属性,其中一个带有转换器以否定属性的值。这是一个存储库您可以克隆并查看代码并进行测试,这可能与我的 Visual Studio 有关。
最初,我认为这可能是竞争条件,并使更改变量的方法同步,但它不起作用。
这是我的列表视图
<ListView ItemsSource="{Binding Items}"
HasUnevenRows="True"
SeparatorVisibility="None"
IsRefreshing="False">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}"/>
<StackLayout Orientation="Horizontal">
<Button Text="One"
HorizontalOptions="CenterAndExpand"
TextColor="Green"
BackgroundColor="White"
BorderColor="Green"
BorderWidth="1"
WidthRequest="150" />
<Button Text="Two"
HorizontalOptions="CenterAndExpand"
BackgroundColor="Green"
TextColor="White"
Command="{Binding TestCommand}"
WidthRequest="150"
IsVisible="{Binding TestVariable, Converter={StaticResource negate}}" />
<Button Text="Three"
HorizontalOptions="CenterAndExpand"
BackgroundColor="Red"
Command="{Binding TestCommand}"
TextColor="White"
WidthRequest="150"
IsVisible="{Binding TestVariable}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
视图模型
public class ListViewTestModel : BaseViewModel
{
private List<ListItemTestModel> items;
public List<ListItemTestModel> Items
{
get => items;
set
{
SetValue(ref items, value);
}
}
public ListViewTestModel()
{
List<ListItemTestModel> itemList = new List<ListItemTestModel>();
for (int i = 0; i < 40; i++)
{
itemList.Add(new ListItemTestModel { Name = "Test" });
}
Items = itemList;
}
}
以及绑定到 listView 中每个项目的另一个视图模型
public class ListItemTestModel : BaseViewModel
{
private bool testVariable;
public string Name { get; set; }
public bool TestVariable
{
get
{
return testVariable;
}
set
{
SetValue(ref testVariable, value);
}
}
public Command TestCommand { get; set; }
public ListItemTestModel()
{
TestCommand = new Command(() =>
{
TestMethod();
});
}
public void TestMethod()
{
TestVariable = !TestVariable;
}
}
基本视图模型
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetValue<T>(ref T backingField, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(backingField, value))
{
return;
}
backingField = value;
OnPropertyChanged(propertyName);
}
}
以及页面的代码隐藏
public partial class MainPage : ContentPage
{
public ListViewTestModel ViewModel { get; }
public MainPage()
{
ViewModel = new ListViewTestModel();
BindingContext = ViewModel;
InitializeComponent();
}
}
解决方案
我建议 listview Caching Strategy 可能会解决这个问题,ListView 的默认值为 RetainElement,因此在 ListView 中使用CachingStrategy="RecycleElement"。
关于listview缓存策略,可以看一下:
推荐阅读
- jquery - JQuery 在鼠标悬停时更改文本并在鼠标悬停时返回原始文本
- scala - spark解析json字段并匹配不同的案例类
- asp.net - 如何从 JwtSecurityTokenHandler 获取日志输出?
- c++ - 当不使用 break 语句输入负值时,C++ 特殊值类型循环必须退出
- javascript - 在父级 Vuejs 中从子级更改道具
- ios - Xcode 10:代码签名身份中的不代码签名选项在哪里
- logging - ASP.NET Core 日志记录 - 过滤掉系统项
- javascript - 如何在javascript中为for循环输出添加空格?
- java - org.hibernate.MappingException 找不到具有逻辑名称注释 getter 的列
- android - 验证交易测试 Google 应用内购买的哪个 URL?