1

I would like to programmatically change the SelectedIndex of a FlipView. My ViewModel looks like this:

public class MyViewModel : ViewModelBase {
   private int _flipViewIndex;

   public int FlipViewIndex
   {
      get { return _flipViewIndex; }
      private set { Set(ref _flipViewIndex, value); }
   }

   private string _logText;

   public string LogText
   {
      get { return _logText; }
      private set { Set(ref _logText, value); }
   }

   public async void Log(string text)
   {
      CoreDispatcher dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
      if (dispatcher.HasThreadAccess)
      {
         LogText += text + "\n";
      }
      else
      {
         await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => Log(text));
      }
   }

   public async void SetIndex(int index)
   {
      CoreDispatcher dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
      if (dispatcher.HasThreadAccess)
      {
         FlipViewIndex = index;
      }
      else
      {
         await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => SetIndex(index));
      }
   }
}

Set() raises INotifyPropertyChanged.PropertyChanged().

My XAML looks like this:

<views:BaseView>
 <Grid DataContext="{StaticResource ViewModel}">
  <FlipView SelectedIndex="{Binding FlipViewIndex}">
    <Control1 />
    <Control2 />
    <Control3 />
   </FlipView>
   <TextBlock Text="{Binding LogText}" />
  </Grid>
</views.BaseView>

The View and ViewModel appear to be bound correctly. When I call ViewModel.Log("foo") from my controller, the TextBlock's text is updated to reflect the change.

The problem is that when I call ViewModel.SetIndex(n), FlipView's SelectedIndex doesn't get updated to n, it just stays at 0. Any ideas why this might be happening?

Daniel A. Thompson
  • 1,904
  • 1
  • 17
  • 26
  • Sure doesn't seem right. Is using SelectedItem an option? – Jerry Nixon Feb 03 '15 at 01:34
  • Hi Jerry - I haven't tried it, but we would prefer to avoid using SelectedItem so that we can more cleanly decouple the ViewModel from the rest of the app. – Daniel A. Thompson Feb 04 '15 at 21:27
  • You know your app better than I do. But since we're talking about it, it's worth pointing out that a reference to the selected item has far less to do with the view than the ordinal position of it in a sorted list. Of my users, I say the selected item is Jerry. Of my users I say the selected index is... what? Do I account for visibility? Do I account for sort? Do I account for filter? SelectedItem is straight forward. SelectedIndex mixes concerns so the view model is intimate with the view. Is that wrong? MVVM is flexible, there's no wrong. But is Index more de-coupled? Not in my opinion. – Jerry Nixon Feb 05 '15 at 20:37
  • Point taken. In this instance, the contents of the FlipView are static, so it's a pretty straightforward interface. Essentially, we're using the FlipView to host elements that indicate, in order, outcome 1, current situation, and outcome 2. We start on index 1 (current situation) and we want to programmatically flip the view to an index that depends on an unrelated process's outcome: either to index 0 (outcome 1) or index 2 (outcome 2) . continued... – Daniel A. Thompson Feb 05 '15 at 21:34
  • The visual elements are strictly visual; you could think of them as just a picture or something. Can `SelectedIndex` not be bound? I feel like I'm taking crazy pills (or just overlooking something extremely simple)... – Daniel A. Thompson Feb 05 '15 at 21:34

1 Answers1

3

I have just confirmed that this works.

<FlipView FontSize="200"
          ItemsSource="{Binding Items}"
          SelectedIndex="{Binding Index, Mode=TwoWay}" />

Just doing this.

<Page.BottomAppBar>
    <CommandBar>
        <AppBarButton Command="{Binding PrevCommand}"
                      Icon="Previous"
                      Label="Previous" />
        <AppBarButton Command="{Binding NextCommand}"
                      Icon="Next"
                      Label="Next" />
    </CommandBar>
</Page.BottomAppBar>

And this view model

public class MyViewModel : BindableBase
{
    public MyViewModel()
    {
        foreach (var item in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 })
            this.Items.Add(item);
    }

    ObservableCollection<int> _Items = new ObservableCollection<int>();
    public ObservableCollection<int> Items { get { return _Items; } }

    int _Index = default(int);
    public int Index { get { return _Index; } set { base.SetProperty(ref _Index, value); } }

    public DelegateCommand PrevCommand
    {
        get { return new DelegateCommand(() => { this.Index--; }); }
    }

    public DelegateCommand NextCommand
    {
        get { return new DelegateCommand(() => { this.Index++; }); }
    }
}

Works. Really does.

Best of luck!

Jerry Nixon
  • 31,313
  • 14
  • 117
  • 233