В следующем примере показано, как переключаться между всеми вкладками документов пользовательского DocumentManager
при нажатии комбинации клавиш Ctrl + Right (в этом примере элемент управления DocumentManager
требуется для фокусировки) :
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
Реализация взята из Документы Microsoft: шаблоны - приложения WPF с шаблоном проектирования Model-View-ViewModel :
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
}