变量范围我有一个非常奇怪的问题。名为“TodoListView”的Listview是通过xaml定义的,它的ItemSource是从SQListe数据库填充的。作品。在ListView内部,我有一个ViewCell来按行显示数据。
<ContentPage ... x:Class="JanitorPro.MainPage" ...>
<StackLayout>
<ListView x:Name="TodoListView" Margin="20" ItemSelected="OnListItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label Text="{Binding name}" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" />
<Switch HorizontalOptions="End" IsToggled="{Binding done}" Toggled="DoneSwitchToggled"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
代码隐藏看起来像这样(删除了一些不相关的部分):
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
protected override async void OnAppearing()
{
base.OnAppearing();
// load Database
TodoListView.ItemsSource = await App.TodoDatabase.GetItemsAsync("SELECT * FROM [TodoItem]");
}
async void OnReloadButtonClicked(object sender, EventArgs e)
{
Debug.WriteLine("Reload Button Click");
TodoListView.ItemsSource = await App.TodoDatabase.GetItemsAsync("SELECT * FROM [TodoItem]");
Debug.WriteLine("Reload done.");
}
async void OnListItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem != null)
{
await Navigation.PushAsync(new TodoItemPage
{
BindingContext = e.SelectedItem as TodoItem
});
}
}
private void DoneSwitchToggled(object sender, ToggledEventArgs e)
{
// TodoItem i = null;
TodoItem i = TodoListView.SelectedItem;
if (i != null)
{
Debug.WriteLine("Toggle: {0}", i.id);
}
}
}
}
奇怪有两个阶段。在我插入DoneSwitchToggled事件处理程序之前,TodoListView.ItemsSource的每个出现都在TodoListView下得到一个红色下划线,并提示“当前上下文中不存在名称TodoListView”。好吧,我认为VS不够聪明,无法在xaml文件中找到定义,因为尽管有警告,程序编译并运行正常。 TodoListView被初始化并正确显示底层数据库的行,因此它在运行时显然存在。
当我将DoneSwitchToggled事件处理程序添加到XAML和代码隐藏时,事情变得疯狂。突然之间,程序将不再编译,但是使用CS0103错误进行挽救“名称”TodoListView“在当前上下文中不存在”。错误出现三次,行号指向onAppearing()和OnReloadButtonClicked()中TodoListView的其他出现。咦?如何在事件处理程序中添加变量引用如何在完全不同的方法中使该变量无效?好吧,之前有一些变量可疑(仍然不知道是什么......),但它确实有效。现在它已经不复存在了,对我来说没有任何意义。此外,如果我在DoneSwitchToggled事件处理程序中注释掉违规行,并为i插入虚拟定义,如下所示:
TodoItem i = null;
// TodoItem i = TodoListView.SelectedItem;
一切都像以前一样,VS仍然强调TodoListView的其他外观,但现在程序构建并再次运行正常。
谁能解释这种效果,并告诉我我的代码有多正确?我认为目标很明确:DoneSwitchToggled应该将开关值写回到数据库中(并执行我的剥离示例中未显示的其他处理),虽然“sender”对象被正确设置为引用我的按钮,但是发现无法访问底层数据绑定,因为不幸的是ToggledEventArgs似乎只传递了开关位置“true”或“false”,但是 - 与OnListItemSelected事件处理程序不同 - 不通过第二个参数传递对绑定行的任何引用。所以我的想法是为此目的使用ListView.SelectedItem。
最后我自己弄清楚了。这似乎是VS 2017中的一个小故障.TodoListView没有任何问题,所以错误CS0103误导了废话。
VS的真正含义是错误CS0266。 TodoListView由通用列表定义
List<TodoItem>
访问SelectedItem我需要对其进行类型转换:
TodoItem i = (TodoItem)TodoListView.SelectedItem;
这个添加,所有错误都消失了,应用程序代码构建正常。
顺便说一句,不幸的是,这种方法来获取Switch已被翻转的项目已证明不起作用,TodoListView总是为SelectedItem返回null,似乎ListView控件没有看到按下按钮。需要找到一种不同的方法来查找交换机下方的列表项以获取绑定的行ID。