Search code examples
c#wpfxamlmvvmavalondock

How to go from one tab to another tab in AvalonDock when a button or key is pressed?


I created a view from SampleDockWindowView and I like to go to the other view created window when a button is pressed.

I've already tried Application.Current.Windows. This array is just empty.

window2 win2= new window2();
        win2.Show();

I would image something like this but with avalondock tabs. not necessarily new window but just to show the existing window when a button is pressed


Solution

  • The following example shows how to cycle through all document tabs of the custom DocumentManager when a Ctrl + Right key combination is pressed (in this example the DocumentManager control is required to have focus):

    MainWindow.xaml

    <Window>
      <Window.DataContext>
        <local:MainViewModel />
      </Window.DataContext>
    
      <Grid>
    
        <!-- 
          Border to capture keyboard events of the DocumentManager UserControl. 
          To capture keys in a different scope i.e. more globally, 
          move the input bindings to a parent control.
        -->
        <Border>
          <!-- Bind keyboard keys to a ICommand. -->
          <Border.InputBindings>
            <KeyBinding Key="Right" 
                        Modifiers="Control" 
                        Command="{Binding NavigateToNextDocument}"/>
          </Border.InputBindings>
    
          <DocumentManager x:Name="DocumentManager" />
        </Border>
      </Grid
    </Window>
    

    DocumentManager.xaml

    <UserControl>    
      <Grid>
        <xceed:DockingManager DocumentsSource="{Binding DocumentMainPool}">
    
          <xceed:DockingManager.LayoutItemTemplate>
            <DataTemplate DataType="{x:Type local:Document}">
              <TextBlock Text="{Binding Title}" />
            </DataTemplate>
          </xceed:DockingManager.LayoutItemTemplate>
    
          <xceed:DockingManager.LayoutItemContainerStyle>
            <Style TargetType="xcad:LayoutItem">
              <Setter Property="Title"
                      Value="{Binding Model.Title}" />
              <Setter Property="ToolTip"
                      Value="{Binding Model.Title}" />
    
              <!-- Important -->
              <Setter Property="IsSelected"
                      Value="{Binding Model.IsSelected, Mode=TwoWay}" />
            </Style>
          </xceed:DockingManager.LayoutItemContainerStyle>
    
          <xceed:LayoutRoot>
            <xceed:LayoutPanel>
              <xceed:LayoutDocumentPaneGroup>
    
                <!-- *** Dynamically created content (by view model) *** -->
                <xceed:LayoutDocumentPane />
    
              </xceed:LayoutDocumentPaneGroup>
            </xceed:LayoutPanel>
          </xceed:LayoutRoot>
        </xceed:DockingManager>
    
      </Grid>
    </UserControl>
    

    MainViewModel.cs

    class MainViewModel : INotifyProeprtyChanged
    {
      public MainViewModel()
      {
        this.DocumentMainPool = new ObservableCollection<IDocument>() 
        {
          new Document("First Document"), 
          new Document("Second Document")
        };
      }
    
      private ObservableCollection<IDocument> documentMainPool;
      public ObservableCollection<IDocument> DocumentMainPool
      {
        get => this.documentMainPool;
        set
        {
          this.documentMainPool = value;
          OnPropertyChanged();
        }
      }
    
      public ICommand NavigateToNextDocument => new RelayCommand(param => CycleNextDocuments());
    
      private void CycleNextDocuments()
      {
        // Only one or no document -> nothing to cycle through
        if (this.DocumentMainPool.Count < 2)
        {
          return;
        }
    
        IDocument currentlySelectedDocument = this.DocumentMainPool.FirstOrDefault(document => document.IsSelected);
        int currentDocumentIndex = this.DocumentMainPool.IndexOf(currentlySelectedDocument);
    
        // If last document reached, show first again
        if (currentDocumentIndex == this.DocumentMainPool.Count - 1)
        {
          this.DocumentMainPool.FirstOrDefault().IsSelected = true;
          return;
        }
    
        IDocument nextDocument = this.DocumentMainPool
          .Skip(currentDocumentIndex + 1)
          .Take(1)
          .FirstOrDefault();
        nextDocument.IsSelected = true;
      }
    
      public event PropertyChangedEventHandler PropertyChanged;
      protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
      {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    }
    

    IDocument.cs

    // Important: IsSelected must raise PropertyChanged
    public interface IDocument : INotifyPropertyChanged
    {
      string Title { get; set; }
      bool IsSelected { get; set; }
    }
    

    Document.cs

    public class Document : IDocument
    {
      public Document(string title)
      {
        this.Title = title;
      }
    
      #region Implementation of IDocument
    
      public string Title { get; set; }
    
      private bool isSelected;
      public bool IsSelected
      {
        get => this.isSelected;
        set
        {
          this.isSelected = value;
          OnPropertyChanged();
        }
      }
    
      public event PropertyChangedEventHandler PropertyChanged;
      protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
      {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    
      #endregion
    }
    

    RelayCommand.cs
    Implementation taken from Microsoft Docs: Patterns - WPF Apps With The Model-View-ViewModel Design Pattern:

    public class RelayCommand : ICommand
    {
        #region Fields 
        readonly Action<object> _execute;
        readonly Predicate<object> _canExecute;
        #endregion // Fields 
        #region Constructors 
        public RelayCommand(Action<object> execute) : this(execute, null) { }
        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            _execute = execute; _canExecute = canExecute;
        }
        #endregion // Constructors 
    
        #region ICommand Members 
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
        public void Execute(object parameter) { _execute(parameter); }
        #endregion // ICommand Members 
    }