我有一个ListView,绑定到ObservableCollection,其模板包含通过用户交互可见/不可见的视图。但是,可见性切换不能按预期工作 - 最初不可见的项目保持不可见,而最初可见的一些项目可以正确地来回切换。我不知道哪里出了问题。
为了追踪问题,我创建了一个极其简化的原始代码版本,并附加了一个绑定(在第2列中)以帮助追踪问题。以下简要介绍了这个简化版本:
ListView的每一行都有一个三列网格。第一列包含两个标签,它们的可见性被切换,即在任何给定时间只能看到一个标签。第二列包含一个标签,其文本与应可见的标签相同。第三列包含一个按钮,用于切换第一列中标签的可见性。
在Windows和Android平台上加载页面呈现正常。命中所有命令,并在它们应该调用所有属性的setter。
在UWP上,按下切换按钮后,该行中的所有文本内容都会消失,包括按钮的文本!再次按下切换按钮可使第一列(最初可见)中的文本重新出现,但所有其他文本仍然不可见。
在Win8上,除了按钮文字仍然存在外,它大致相同。
在Android上,切换功能正常,直到选中并删除某个项目。之后,除了最后一项,删除之前的任何项目以及删除之前已切换的任何项目时,第一列在切换显示第二个标签时变为空白,而第二列行为正确。因此,例如,如果我切换Baz,然后删除Bar,则会发生以下情况:Foo,Baz和Kevin的行为与我期望的一样,但Dave将在Dave1和第一列中的任何内容之间切换。
这种行为让我感到非常难过,所以如果有人知道发生了什么,我将非常感激。
这是一个Xamarin.Forms可移植项目,我使用MVVMLightLibs作为ModelBase / RelayCommand,这是我的代码(全部在便携式库中)
查看:
<StackLayout>
<ListView ItemsSource="{Binding TestList}"
SelectedItem="{Binding SelectedItem}">
<ListView.RowHeight>
<OnPlatform x:TypeArguments="x:Int32" iOS="90" Android="90" WinPhone="100" />
</ListView.RowHeight>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView Padding="5">
<Grid HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding Text1}" IsVisible="{Binding Text1Visible}"/>
<Label Text="{Binding Text2}" IsVisible="{Binding Text2Visible}"/>
<Label Text="{Binding CurrentText}" Grid.Column="1"/>
<Button Grid.Column="2"
Text="Toggle"
Command="{Binding Source={x:Reference MainPage}, Path=BindingContext.ToggleCommand}"
CommandParameter="{Binding}"/>
</Grid>
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Text="Delete selected" Command="{Binding DeleteCommand}"/>
</StackLayout>
视图模型:
public class MainViewModel : ViewModelBase
{
public ObservableCollection<MyClass> TestList { get; set; }
public MyClass SelectedItem { get; set; }
public RelayCommand<MyClass> ToggleCommand { get; set; }
public RelayCommand DeleteCommand { get; set; }
public MainViewModel()
{
ToggleCommand = new RelayCommand<MyClass>(ToggleClicked);
DeleteCommand = new RelayCommand(DeleteSelected);
TestList = new ObservableCollection<MyClass>();
TestList.Add(new MyClass { Text1 = "Foo1", Text2 = "Foo2", Text1Visible = true });
TestList.Add(new MyClass { Text1 = "Bar1", Text2 = "Bar2", Text1Visible = true });
TestList.Add(new MyClass { Text1 = "Baz1", Text2 = "Baz2", Text1Visible = true });
TestList.Add(new MyClass { Text1 = "Dave1", Text2 = "Dave2", Text1Visible = true });
TestList.Add(new MyClass { Text1 = "Kevin1", Text2 = "Kevin2", Text1Visible = true });
}
private void DeleteSelected()
{
if (SelectedItem != null)
TestList.Remove(SelectedItem);
}
private void ToggleClicked(MyClass myclass)
{
myclass.Text2Visible = myclass.Text1Visible;
myclass.Text1Visible = !myclass.Text1Visible;
}
}
型号:
public class MyClass : INotifyPropertyChanged
{
private bool _t1v;
private bool _t2v;
private string _text1;
private string _text2;
private string _currentText;
public string Text1
{
get { return _text1; }
set
{
_text1 = value;
RaisePropertyChanged(nameof(Text1));
}
}
public string Text2
{
get { return _text2; }
set
{
_text2 = value;
RaisePropertyChanged(nameof(Text2));
}
}
public string CurrentText
{
get { return _currentText; }
set
{
_currentText = value;
RaisePropertyChanged(nameof(CurrentText));
}
}
public bool Text1Visible
{
get { return _t1v; }
set
{
_t1v = value;
// Set the current text to the one that should be visible
if (_t1v)
CurrentText = Text1;
else
CurrentText = Text2;
RaisePropertyChanged(nameof(Text1Visible));
}
}
public bool Text2Visible
{
get { return _t2v; }
set
{
_t2v = value;
// Set the current text to the one that should be visible
if (_t2v)
CurrentText = Text2;
else
CurrentText = Text1;
RaisePropertyChanged(nameof(Text2Visible));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}