0

Using AvalonDock, I am experiencing a problem that seems somewhat strange to me.

The situation

I have an ObservableCollection of ViewModels bound to the DocumentSource property of the DockingManager. I add items to this collection, and thus documents are added to the DockingManager: the correct View (UserControl) for the ViewModel is picked because I specified a DataTemplate for each ViewModel.

The problem

The above all works. However, when I change between tabs in AvalonDock, the View is recreated each time a tab is selected (InitializeComponent() gets called). This leads to problems cause selections are not persisted, and static UIElements cause exceptions when added somewhere while already in use.

I am unsure what I am doing wrong, even after spending many hours on this issue. Using a template selector instead of the current way of choosing the right view has no effect.

Any ideas are welcome!

Edit 1

Interestingly, I have better results with a version of AvalonDock I had lying around here. That is version 2.0.0 from some time in 2016, as opposed to the current version of 3.5.0. The exact same code works as I would expect with the old version, and does not with the latest version.

Implementation

Below is a somewhat abbreviated version of my implementation of AvalonDock.

The main view:

<Window ... >
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:Workspace1}">
            <local:Workspace1View />
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <StackPanel Orientation="Horizontal">
            <Button Content="1" Command="{Binding Path=OpenWorkspace1Command}" Margin="2" />
        </StackPanel>
        <ad:DockingManager 
            Grid.Row="1" 
            DocumentsSource="{Binding Path=Workspaces}" 
            AllowMixedOrientation="True">
        </ad:DockingManager>
    </Grid>
</Window>

The main ViewModel:

public class MainWindowViewModel : ViewModelBase
{
    private RelayCommand _openWorkspace1Command;

    public ObservableCollection<WorkspaceBase> Workspaces { get; } = new ObservableCollection<WorkspaceBase>();

    public ICommand OpenWorkspace1Command => _openWorkspace1Command ?? (_openWorkspace1Command = new RelayCommand(() => 
    {
        Workspaces.Add(new Workspace1());
    }));
}

Workspace View (note that when scrolling down in the ListView, when leaving the tab and returning, the scroll position is reset, cause the View is recreated):

<UserControl ...>
    <Grid>
        <ListView ItemsSource="{Binding Items}" />
    </Grid>
</UserControl>

Workspace ViewModel:

public class Workspace1 : WorkspaceBase
{
    public override void OnWorkspaceOpened() { }

    public List<string> Items { get; }

    public Workspace1()
    {
        Items = new List<string>();

        for (int i = 0; i < 10000; i++) Items.Add("Item " + i.ToString());
    }
}

And finally the abstract WorkspaceBase class:

public abstract class WorkspaceBase : ViewModelBase, IDisposable
{
    RelayCommand _closeCommand;

    public virtual string DisplayName { get; }
    public virtual ImageSource Icon { get; }
    public virtual bool HideOnClose { get; } = false;
    public virtual bool IsCloseable { get; } = true;

    protected WorkspaceBase() { }

    public ICommand CloseCommand => _closeCommand ?? (_closeCommand = new RelayCommand(CloseCommand_executed, CloseCommand_canExecute));

    public delegate void WorkspaceRequestCloseEventHandler(object sender, WorkspaceRequestCloseEventArgs e);

    public event WorkspaceRequestCloseEventHandler RequestClose;

    void CloseCommand_executed()
    {
        Dispose();
        this.RequestClose?.Invoke(this, new WorkspaceRequestCloseEventArgs());
    }

    private bool CloseCommand_canExecute()
    {
        return IsCloseable;
    }

    public abstract void OnWorkspaceOpened();

    public void Dispose()
    {
        this.OnDispose();
    }

    protected virtual void OnDispose()
    {
    }
}
mennowo
  • 384
  • 2
  • 12

1 Answers1

1

Seems like this is an issue with AvalonDock itself. This version of the control fixes the issues described: https://github.com/Dirkster99/AvalonDock.

mennowo
  • 384
  • 2
  • 12
  • are you sure is it solved? I am facing this issue with the last version, the viewmodel is created instead of be taken from AnchorablesSource – Perry May 22 '21 at 16:16
  • Sure is always relative in this context. However, I have not had these issues since I started using the 'Dirkster99' version of AvalonDock. Note that I am using DocumentsSource and not AnchorablesSource. – mennowo May 23 '21 at 18:07
  • I solved it, the problem was that I was defining the datacontext inside the xaml – Perry May 25 '21 at 12:03