SelectedItem must always be set to a valid value

2019-08-23 05:01发布

问题:

I have two viewmodel, on the first viewmodel i have a listbox:

<ListBox x:Name="MainMenu" toolkits:TiltEffect.IsTiltEnabled="True" 
 SelectedItem="{Binding SelectedItem, Mode=TwoWay}" 
 ItemTemplate="{StaticResource MainMenu}" 
 ItemsSource="{Binding Categories}" Margin="0,97,0,0" 
 Tap="MainMenu_Tap">

In the second page, i have a listpicker

<toolkit:ListPicker Margin="0,153,0,0" Background="{StaticResource PhoneAccentBrush}" VerticalAlignment="Top"
 ItemsSource="{Binding Categories}"
 SelectedItem="{Binding Item}"
 ItemTemplate="{StaticResource CategorySelector}"
 FullModeHeader="Category" 
 FullModeItemTemplate="{StaticResource FullCategorySelector}"
 BorderBrush="{StaticResource PhoneAccentBrush}"/>

What i want is when I navigate to second page, the selected item in the first page will be selected in the second page. But I always get the selected item must always set to a valid value when I navigate to second page.

first viewmodel

private CategoryModel _selectedItem = null;
public CategoryModel SelectedItem
{
    get { return _selectedItem; }
    set
    {
        if (_selectedItem == value)
        {
            return;
        }

        var oldValue = _selectedItem;
        _selectedItem = value;

        RaisePropertyChanged("SelectedItem", oldValue, value, true);
    }
}

second viewmodel

private CategoryModel _item = null;
public CategoryModel Item
{
    get { return _item; }
    set
    {
        if (_item == value)
        {
            return;
        }

        var oldValue = _item;
        _item = value;

        // Update bindings, no broadcast
        RaisePropertyChanged("Item");
    }
}

EDIT

When I change the listpicker in the second page to Listbox, it works pretty well.

So this is an issue enter link description here. How should I do to get this thing work with the listpicker?

回答1:

I think you're confusing views and viewmodels.

Because you're binding the selected item in XAML, when the XAML is parsed and the page created it's trying to bind to an item in a collection which hasn't been created yet. This is why the comments on the bug suggest a work around when setting this in code behind.

In your Tap handler on the first page, I assume that you're passing some details of the selected item to the second page. You could, therefore, remove the XAML binding of the selected item and in the OnNavigatedTo event handler on the second page set the binding in code, once you know the ItemsSource has been populated.

Alternatively, you could consider having the two pages share the same viewmodel instance.



回答2:

ListPicker uses Items.IndexOf to get the index of item instance that should select.

If the instance does not match (it is not an object instance from the collection) the IndexOf will return -1 and the InvalidOperationException is thrown with the message: "SelectedItem must always be set to a valid value".

Override Equals method of the type in the collection and it will work as expected.

Example:

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

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

         return false;
 }

Hope it helps