0

As far as I can tell AvalonDock has two ways to add ViewModels. The AnchorablesSource and DocumentsSource properties. I simply want to be able to doc my current ViewModels in the way FileViewModels are in the LayoutDocumentPane without deriving from FileViewModel. The problem is if you don't derive from FileViewModel the window looses all of its labels. Also if you use the AnchorableSource instead of DocumentSource, when you add a new window it is added to the right side of the main and not as a tab to the documentspane. Does anyone know how to achieve this desired result?

Source code reference

http://avalondock.codeplex.com/

Here is the FileViewModel that comes with the AvalonDock test application

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

}

}

Here is the main window xaml from the test application

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

Here is the ViewModel for the main window with edits I made it wont match the xaml posted here as that is it in the original form. I simply tried to replace FileViewModel with my own DockingViewModel.

    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;
    }



}
Matt Rockwell
  • 456
  • 1
  • 6
  • 20
Bob
  • 1,065
  • 2
  • 16
  • 36
  • What is FileViewModel? Please improve your question providing your (relevant) code. – dymanoid Feb 24 '15 at 15:44
  • 2
    @dymanoid If you use AvalonDock, then you would know what it is. As it is part of the project I will link to the project but I am not pasting in the projects thousands of lines of code – Bob Feb 24 '15 at 15:46
  • Please refer to the topic [How do I ask a good question?](http://stackoverflow.com/help/how-to-ask). Please note that you need to provide [a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). And, by the way, `AvalonDock` **implementation** has nothing to do with any FileViewModel. – dymanoid Feb 24 '15 at 15:52
  • 1
    @dymanoid I added the files requested. – Bob Feb 24 '15 at 16:03

0 Answers0