Listpicker错误提示:必须始终将SelectedItem设置为有效值

10

我在一个Windows Phone 7应用程序中有一个页面,用户可以编辑或删除Transaction对象。 Transaction对象是一个Linq-to-Sql类,与Account类和Category类有关系。 在页面中,我使用ListPicker让用户选择给定交易的帐户和类别,如下所示:

<toolkit:ListPicker Grid.Row="1" FullModeHeader="Choose the Account" FullModeItemTemplate="{StaticResource FullModeItemTemplate}" ExpansionMode="FullScreenOnly" Background="#26000000" Margin="10,0,10,0" Name="Account" SelectedItem="{Binding Account, Mode=TwoWay}" Tap="ListPicker_Tap" />

<toolkit:ListPicker Grid.Row="7" FullModeHeader="Choose the Category" FullModeItemTemplate="{StaticResource FullModeItemTemplate}" ExpansionMode="FullScreenOnly" Background="#26000000" Margin="10,0,10,0" Name="Category" SelectedItem="{Binding Category, Mode=TwoWay}" Tap="ListPicker_Tap" />

ListPicker_Tap事件是针对Windows Phone的WPF Toolkit 2011年8月版本中一个错误的修复方法,它只是这样的:

    private void ListPicker_Tap(object sender, System.Windows.Input.GestureEventArgs e)
    {
        ListPicker lp = (ListPicker)sender; 
        lp.Open();
    }
如果用户编辑交易,一切都正常,但是如果用户试图删除它,我会收到一个错误,提示“SelectedItem必须始终设置为有效值”。
以下是当用户在TransactionPage.xaml.cs中的应用栏中单击删除按钮时的代码:
    private void appBarDelete_Click(object sender, EventArgs e)
    {
        MessageBoxResult result = MessageBox.Show("Are you sure?\n", "Confirm", MessageBoxButton.OKCancel);

        if (result == MessageBoxResult.OK)
        {
            App.ViewModel.DeleteTransaction(transaction);
        }

        NavigationService.GoBack();
    }

我的ViewModel.DeleteTransaction方法:

    public void DeleteTransaction(Transaction transaction)
    {
        AllTransactions.Remove(transaction);
        transactionRepository.Delete(transaction);
    }

我的transactionRepository.Delete方法:

    public void Delete(Transaction transaction)
    {
        Context.Transactions.DeleteOnSubmit(transaction);
        Context.SubmitChanges();
    }

在执行Context.SubmitChanges()时,我收到了错误提示,调试指向Transaction类中的NotifyPropertyChanged,发生错误的行是这行:

    protected virtual void SendPropertyChanged(String propertyName)
    {
        if ((this.PropertyChanged != null))
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
在propertyName属性中,它的值是"Category"。看起来当删除对象时,会发送类别和账户的propertychanged事件,由于列表选择器处于双向模式,它在处理时遇到了一些麻烦。我该怎么修复它?我需要一些帮助。

你能附上完整的XAML吗?或者如果太长了,部分XAML也可以,只要我们能看到 {Binding Account, Mode=TwoWay}{Binding Category, Mode=TwoWay} 所指的内容即可。 - Amry
4个回答

12

这个错误也可能是由于XAML属性的顺序引起的:

以下代码是错误示范(当设置SelectedItem时,ItemsSource为null会抛出异常):

<toolkit:ListPicker DisplayMemberPath="Title" SelectionMode="Single" 
SelectedItem="{Binding SelectedCategory, Mode=TwoWay}"
ItemsSource="{Binding Categories}" />

这是因为itemssource被先初始化了:

<toolkit:ListPicker DisplayMemberPath="Title" SelectionMode="Single" 
ItemsSource="{Binding Categories}"
SelectedItem="{Binding SelectedCategory, Mode=TwoWay}" />

1
是的,这显然是.NET控件中的一个错误,它应该能够处理这样的情况而不会崩溃...(在设计自己的控件时要考虑到这个问题 :)) - Rico Suter
这个解决方案对我有用。 - Klaus Nji

3

如果实例不匹配(它不是集合中的对象实例),IndexOf将返回-1,InvalidOperationException将抛出消息:“必须始终将SelectedItem设置为有效值”。

覆盖集合中项目类型的Equals方法,它将按预期工作。

示例:

public override bool Equals(object obj)
{
         var target = obj as ThisType;
         if (target == null)
             return false;

         if (this.ID == target.ID)
             return true;

         return false;
 }

希望这有所帮助。

2

只有两个检查会在SelectedItem上引发InvalidOperationException异常

  1. Listpicker的Items为空(声明式:属性顺序很重要,如果SelectedItem必须在ItemSource之后出现;编程式:确保ItemSource已加载)
  2. Listpicker对Items应用IndexOf来设置选定的项目。因此,如果需要,请确保覆盖Equals方法。

使用监视器调试Listpicker.Items和覆盖的Equals方法将帮助我们识别问题。


请注意:如果您绑定到子属性,您还需要初始化它,否则您将遇到相同的错误(因为您的第一个属性为空)。 - kamranicus

1
问题在于ListPicker要求SelectedItem是一个ListPickerItem,而您正在将其绑定到Transaction类型的对象。您可以通过绑定到SelectedIndex属性并根据索引从您的ViewModel中选择适当的对象来解决此问题。

此外,如果您定义了Tap处理程序的原因是因为ListPicker嵌入了ScrollViewer时不会打开,那么请查看补丁ID 10247。如果您使用该补丁重新编译工具包,则可以修复该问题。


ListPicker.SelectedItem 也可以绑定到数据对象,而不仅仅是 ListPickerItem - Amry
@Amry 你尝试过这样做吗?我曾经遇到过完全相同的问题,不得不使用“SelectedIndex”进行解决。 - Praetorian
如果ListPicker是数据绑定的,那么使用带有SelectedItem的数据对象应该可以正常工作。也许你可以针对你的情况开一个新问题。 :) - Amry
原来这个问题之前已经被问过了(https://dev59.com/9lLTa4cB1Zd3GeqPbpbw)。绑定到一个显示简单字符串的ListPicker确实可以工作,但我从未成功地将绑定应用于更复杂的数据对象。 - Praetorian
@Praetorian,这不太优雅,它直接阻止了列表和对象之间的双向绑定,所以我必须编写代码来管理它,希望有一个更简洁的解决方案,但它能工作!我会接受你的答案。谢谢。 - Alaor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接