据我所知,AvalonDock有两种方法可以添加ViewModels。 AnchorablesSource和DocumentsSource属性。我只是希望能够以FileViewModel在LayoutDocumentPane中的方式记录我当前的ViewModel而不从FileViewModel派生。问题是,如果您不从FileViewModel派生,则窗口会丢失其所有标签。此外,如果您使用AnchorableSource而不是DocumentSource,当您添加新窗口时,它将添加到主窗口的右侧,而不是作为文档窗格的选项卡。有谁知道如何实现这个理想的结果?
源代码参考
http://avalondock.codeplex.com/
这是AvalonDock测试应用程序附带的FileViewModel
namespace AvalonDock.MVVMTestApp
{
class FileViewModel : PaneViewModel
{
static ImageSourceConverter ISC = new ImageSourceConverter();
public FileViewModel(string filePath)
{
FilePath = filePath;
Title = FileName;
//Set the icon only for open documents (just a test)
IconSource = ISC.ConvertFromInvariantString(@"pack://application:,,/Images/document.png") as ImageSource;
}
public FileViewModel()
{
IsDirty = true;
Title = FileName;
}
#region FilePath
private string _filePath = null;
public string FilePath
{
get { return _filePath; }
set
{
if (_filePath != value)
{
_filePath = value;
RaisePropertyChanged("FilePath");
RaisePropertyChanged("FileName");
RaisePropertyChanged("Title");
if (File.Exists(_filePath))
{
_textContent = File.ReadAllText(_filePath);
ContentId = _filePath;
}
}
}
}
#endregion
public string FileName
{
get
{
if (FilePath == null)
return "Noname" + (IsDirty ? "*" : "");
return System.IO.Path.GetFileName(FilePath) + (IsDirty ? "*" : "");
}
}
#region TextContent
private string _textContent = string.Empty;
public string TextContent
{
get { return _textContent; }
set
{
if (_textContent != value)
{
_textContent = value;
RaisePropertyChanged("TextContent");
IsDirty = true;
}
}
}
#endregion
#region IsDirty
private bool _isDirty = false;
public bool IsDirty
{
get { return _isDirty; }
set
{
if (_isDirty != value)
{
_isDirty = value;
RaisePropertyChanged("IsDirty");
RaisePropertyChanged("FileName");
}
}
}
#endregion
#region SaveCommand
RelayCommand _saveCommand = null;
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand((p) => OnSave(p), (p) => CanSave(p));
}
return _saveCommand;
}
}
private bool CanSave(object parameter)
{
return IsDirty;
}
private void OnSave(object parameter)
{
Workspace.This.Save(this, false);
}
#endregion
#region SaveAsCommand
RelayCommand _saveAsCommand = null;
public ICommand SaveAsCommand
{
get
{
if (_saveAsCommand == null)
{
_saveAsCommand = new RelayCommand((p) => OnSaveAs(p), (p) => CanSaveAs(p));
}
return _saveAsCommand;
}
}
private bool CanSaveAs(object parameter)
{
return IsDirty;
}
private void OnSaveAs(object parameter)
{
Workspace.This.Save(this, true);
}
#endregion
#region CloseCommand
RelayCommand _closeCommand = null;
public ICommand CloseCommand
{
get
{
if (_closeCommand == null)
{
_closeCommand = new RelayCommand((p) => OnClose(), (p) => CanClose());
}
return _closeCommand;
}
}
private bool CanClose()
{
return true;
}
private void OnClose()
{
Workspace.This.Close(this);
}
#endregion
}
}
以下是来自测试应用程序的主窗口xaml
<Window x:Class="AvalonDock.MVVMTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:avalonDock="http://schemas.xceed.com/wpf/xaml/avalondock"
xmlns:shell="clr-namespace:Microsoft.Windows.Shell;assembly=AvalonDock"
xmlns:local="clr-namespace:AvalonDock.MVVMTestApp"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:sysWindows="clr-namespace:System.Windows;assembly=PresentationCore"
x:Name="mainWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:ActiveDocumentConverter x:Key="ActiveDocumentConverter"/>
<avalonDock:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Menu>
<MenuItem Header="File">
<MenuItem Header="New" Command="{Binding NewCommand}"/>
<MenuItem Header="Open" Command="{Binding OpenCommand}"/>
<Separator/>
<MenuItem Header="Save" Command="{Binding ActiveDocument.SaveCommand}"/>
<MenuItem Header="Save As..." Command="{Binding ActiveDocument.SaveAsCommand}"/>
<Separator/>
<MenuItem Header="Close" Command="{Binding ActiveDocument.CloseCommand}"/>
</MenuItem>
<MenuItem Header="Tools">
<MenuItem Header="Properties" IsChecked="{Binding FileStats.IsVisible, Mode=TwoWay}" IsCheckable="True"/>
</MenuItem>
<MenuItem Header="Layout">
<MenuItem Header="Load" Command="{Binding LoadLayoutCommand, ElementName=mainWindow}"/>
<MenuItem Header="Save" Command="{Binding SaveLayoutCommand, ElementName=mainWindow}"/>
<MenuItem Header="Dump to Console" Click="OnDumpToConsole"/>
</MenuItem>
</Menu><!--AnchorablesSource="{Binding Tools}" DocumentsSource="{Binding Files}"-->
<avalonDock:DockingManager x:Name="dockManager"
AnchorablesSource="{Binding Tools}"
DocumentsSource="{Binding Files}"
ActiveContent="{Binding ActiveDocument, Mode=TwoWay, Converter={StaticResource ActiveDocumentConverter}}"
Grid.Row="1">
<!--<avalonDock:DockingManager.Theme>
<avalonDock:AeroTheme/>
</avalonDock:DockingManager.Theme>-->
<avalonDock:DockingManager.LayoutItemTemplateSelector>
<local:PanesTemplateSelector>
<local:PanesTemplateSelector.FileViewTemplate>
<DataTemplate>
<TextBox Text="{Binding TextContent, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</local:PanesTemplateSelector.FileViewTemplate>
<local:PanesTemplateSelector.FileStatsViewTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding FileSize}"/>
<TextBlock Text="{Binding LastModified}"/>
<TextBox Text="test"/>
</StackPanel>
</DataTemplate>
</local:PanesTemplateSelector.FileStatsViewTemplate>
</local:PanesTemplateSelector>
</avalonDock:DockingManager.LayoutItemTemplateSelector>
<avalonDock:DockingManager.LayoutItemContainerStyleSelector>
<local:PanesStyleSelector>
<local:PanesStyleSelector.ToolStyle>
<Style TargetType="{x:Type avalonDock:LayoutAnchorableItem}">
<!--<Setter Property="Title" Value="{Binding Model.Title}"/>-->
<Setter Property="IconSource" Value="{Binding Model.IconSource}"/>
<Setter Property="Visibility" Value="{Binding Model.IsVisible, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter={x:Static Visibility.Hidden}}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
<Setter Property="IsSelected" Value="{Binding Model.IsSelected, Mode=TwoWay}"/>
<Setter Property="IsActive" Value="{Binding Model.IsActive, Mode=TwoWay}"/>
</Style>
</local:PanesStyleSelector.ToolStyle>
<local:PanesStyleSelector.FileStyle>
<Style TargetType="{x:Type avalonDock:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
<!--<Setter Property="ToolTip" Value="{Binding Model.FilePath}"/>
<Setter Property="CloseCommand" Value="{Binding Model.CloseCommand}"/>
<Setter Property="IconSource" Value="{Binding Model.IconSource}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>-->
</Style>
</local:PanesStyleSelector.FileStyle>
</local:PanesStyleSelector>
</avalonDock:DockingManager.LayoutItemContainerStyleSelector>
<avalonDock:DockingManager.LayoutUpdateStrategy>
<local:LayoutInitializer/>
</avalonDock:DockingManager.LayoutUpdateStrategy>
<avalonDock:LayoutRoot>
<avalonDock:LayoutPanel Orientation="Vertical">
<avalonDock:LayoutDocumentPane/>
<avalonDock:LayoutAnchorablePane Name="ToolsPane" DockHeight="150">
</avalonDock:LayoutAnchorablePane>
</avalonDock:LayoutPanel>
</avalonDock:LayoutRoot>
</avalonDock:DockingManager>
</Grid>
这是主窗口的ViewModel,我对它进行了编辑,它与这里发布的xaml不匹配,因为它是原始形式。我只是尝试用我自己的DockingViewModel替换FileViewModel。
class Workspace : ViewModelBase
{
protected Workspace()
{
}
static Workspace _this = new Workspace();
public static Workspace This
{
get { return _this; }
}
ObservableCollection<FileViewModel> _files = new ObservableCollection<FileViewModel>();
ReadOnlyObservableCollection<FileViewModel> _readonyFiles = null;
public ReadOnlyObservableCollection<FileViewModel> Files
{
get
{
if (_readonyFiles == null)
_readonyFiles = new ReadOnlyObservableCollection<FileViewModel>(_files);
return _readonyFiles;
}
}
//ToolViewModel[] _tools = null;
//public IEnumerable<ToolViewModel> Tools
//{
// get
// {
// if (_tools == null)
// _tools = new ToolViewModel[2];
// return _tools;
// }
//}
ObservableCollection<DockingViewModel> _tools = new ObservableCollection<DockingViewModel>();
ReadOnlyObservableCollection<DockingViewModel> _readonyTools = null;
public ReadOnlyObservableCollection<DockingViewModel> Tools
{
get
{
if (_readonyTools == null)
_readonyTools = new ReadOnlyObservableCollection<DockingViewModel>(_tools);
return _readonyTools;
}
}
FileStatsViewModel _fileStats = null;
public FileStatsViewModel FileStats
{
get
{
if (_fileStats == null)
_fileStats = new FileStatsViewModel();
return _fileStats;
}
}
#region OpenCommand
RelayCommand _openCommand = null;
public ICommand OpenCommand
{
get
{
if (_openCommand == null)
{
_openCommand = new RelayCommand((p) => OnOpen(p), (p) => CanOpen(p));
}
return _openCommand;
}
}
private bool CanOpen(object parameter)
{
return true;
}
private void OnOpen(object parameter)
{
//var dlg = new OpenFileDialog();
//if (dlg.ShowDialog().GetValueOrDefault())
//{
// var fileViewModel = Open(dlg.FileName);
// ActiveDocument = fileViewModel;
//}
}
public FileViewModel Open(string filepath)
{
var fileViewModel = _files.FirstOrDefault(fm => fm.FilePath == filepath);
if (fileViewModel != null)
return fileViewModel;
fileViewModel = new FileViewModel(filepath);
_files.Add(fileViewModel);
return fileViewModel;
}
#endregion
#region NewCommand
RelayCommand _newCommand = null;
public ICommand NewCommand
{
get
{
if (_newCommand == null)
{
_newCommand = new RelayCommand((p) => OnNew(p), (p) => CanNew(p));
}
return _newCommand;
}
}
private bool CanNew(object parameter)
{
return true;
}
private void OnNew(object parameter)
{
_tools.Add(new DockingViewModel("Hulk"));
//_files.Add(new FileViewModel());
//ActiveDocument = _files.Last();
ActiveDocument = _tools.Last();
}
#endregion
#region ActiveDocument
private DockingViewModel _activeDocument = null;
public DockingViewModel ActiveDocument
{
get { return _activeDocument; }
set
{
if (_activeDocument != value)
{
_activeDocument = value;
RaisePropertyChanged("ActiveDocument");
if (ActiveDocumentChanged != null)
ActiveDocumentChanged(this, EventArgs.Empty);
}
}
}
public event EventHandler ActiveDocumentChanged;
#endregion
internal void Close(FileViewModel fileToClose)
{
if (fileToClose.IsDirty)
{
var res = MessageBox.Show(string.Format("Save changes for file '{0}'?", fileToClose.FileName), "AvalonDock Test App", MessageBoxButton.YesNoCancel);
if (res == MessageBoxResult.Cancel)
return;
if (res == MessageBoxResult.Yes)
{
Save(fileToClose);
}
}
_files.Remove(fileToClose);
}
internal void Save(FileViewModel fileToSave, bool saveAsFlag = false)
{
if (fileToSave.FilePath == null || saveAsFlag)
{
var dlg = new SaveFileDialog();
if (dlg.ShowDialog().GetValueOrDefault())
fileToSave.FilePath = dlg.SafeFileName;
}
File.WriteAllText(fileToSave.FilePath, fileToSave.TextContent);
ActiveDocument.IsDirty = false;
}
}