简体   繁体   中英

How to select an item in LongListSelector using the MVVM-pattern?

I'm building application using the MVVM pattern. After clicking on one of the elements I want to see this element's details. I wrote this:

XAML

<phone:LongListSelector ItemsSource="{Binding Data}" 
                        Margin="0,0,0,158"
                        SelectedItem="{Binding SelectedItem}">
    <phone:LongListSelector.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Button>
                <!-- Command="{Binding ShowDetailsAction}"-->
                    <Button.Template>
                        <ControlTemplate>
                            <TextBlock Text="{Binding Text}"></TextBlock>
                        </ControlTemplate>
                    </Button.Template>
                </Button>
            </StackPanel>
        </DataTemplate>
    </phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>

ViewModel:

public IEnumerable SelectedItem
{
    get { return _itemsControl; }
    set
    {
        if (_itemsControl == value)
            return;
        _itemsControl = value;

        // Test
        _mss.ErrorNotification("fd");
    }
}

I tried also using a command, which didn't work, too.

This was the command part:

public ICommand ShowDetailsCommand { get; private set; }

public ViewModel()
{
    _loadDataCommand = new DelegateCommand(LoadDataAction);
    SaveChangesCommand = new DelegateCommand(SaveChangesAction);
    ShowDetailsCommand = new DelegateCommand(ShowDetailsAction);
}

private void ShowDetailsAction(object p)
{
    _mss.ErrorNotification("bla bla");
}

EDIT

ViewModel

private IEnumerable _itemsControl;
public IEnumerable Data
{
  get
  {
    return _itemsControl;
  }
  set
  {
    _itemsControl = value;
    RaisePropertyChanged("Data");
  }
}

protected void RaisePropertyChanged(string propertyName)
{
  PropertyChangedEventHandler handler = PropertyChanged;
  if (handler != null)
    {
      handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

Model

public string Text { get; set; }
public DateTimeOffset Data { get; set; }

EDIT2

private MobileServiceCollection<ModelAzure, ModelAzure> _items;
        private readonly IMobileServiceTable<ModelAzure> _todoTable = App.MobileService.GetTable<ModelAzure>();


private async void RefreshTodoItems()
{
   try
    {
        _items = await _todoTable.ToCollectionAsync();
    }
   catch (MobileServiceInvalidOperationException e)
     {
          _mss.ErrorNotification(e.ToString());
     }
   Data = _items;
}

In your ViewModel, you have:

public IEnumerable SelectedItem
{
get { return _itemsControl; }
set
{
    if (_itemsControl == value)
        return;
    _itemsControl = value;

    // Test
    _mss.ErrorNotification("fd");
}

}

Why is your SelectItem an IEnumerable? Should it not be of type "Model"? Your list is bound to "Data" which should be ObservableList, not IEnumerable. It will provide it's own change notification, so you don't need to.

The list will set the SelectedItem when it gets selected, but if the type is wrong, it won't get set.

Greg

Your Data property looks like

private MobileServiceCollection<ModelAzure, ModelAzure> _itemsControl;
public MobileServiceCollection<ModelAzure, ModelAzure> Data
{
  get
  {
    return _itemsControl;
  }
  set
  {
    _itemsControl = value;
    RaisePropertyChanged("Data");
  }
}

Edited

It seems the SelectedItem property from LongListSelector cannot be bound in WP8 . What you can do is either :

  • Use the derived and fixed custom LongListSelector provided in the link above instead of the default one, which looks like :

     public class LongListSelector : Microsoft.Phone.Controls.LongListSelector { public LongListSelector() { SelectionChanged += LongListSelector_SelectionChanged; } void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e) { SelectedItem = base.SelectedItem; } public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register( "SelectedItem", typeof(object), typeof(LongListSelector), new PropertyMetadata(null, OnSelectedItemChanged) ); private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var selector = (LongListSelector)d; selector.SelectedItem = e.NewValue; } public new object SelectedItem { get { return GetValue(SelectedItemProperty); } set { SetValue(SelectedItemProperty, value); } } } 
  • Register the SelectionChanged event from LongListSelector and call your ViewModel by yourself inside the associated handler/callback :

in your view :

<phone:LongListSelector x:Name="YourLongListSelectorName"
                        ItemsSource="{Binding Data}" 
                        Margin="0,0,0,158"
                        SelectionChanged="OnSelectedItemChanged">

in your code behind :

private void OnSelectedItemChanged(object sender, SelectionChangedEventArgs selectionChangedEventArgs e)
{
    ((YourViewModel)this.DataContext).NewSelectedItemMethodOrWhateverYouWant((ModelAzure)this.YourLongListSelectorName.SelectedItem);
    //or
    ((YourViewModel)this.DataContext).SelectedItem = (ModelAzure)this.YourLongListSelectorName.SelectedItem;
}

Finally your Button command wasn't properly working, because when you use a DataTemplate , the ambiant DataContext is the item itself. Which means that it was looking for your Command into your Model instance, not into your ViewModel instance.

Hope this helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM