Search code examples
c#mvvmwindows-runtimewinrt-xamlmytoolkit

WinRT FlipView.SelectedIndex binding not responding to changes in ViewModel


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?


Solution

  • 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!