使用AvalonDock,我遇到了一个对我来说有些奇怪的问题。
情况
我有一个ObservableCollection的ViewModels绑定到DockingManager的DocumentSource属性。我将项添加到此集合中,因此文档被添加到DockingManager:选择ViewModel的正确View(UserControl),因为我为每个ViewModel指定了一个DataTemplate。
问题
以上都是有效的。但是,当我在AvalonDock中的选项卡之间切换时,每次选择选项卡时都会重新创建视图(调用InitializeComponent())。这会导致问题导致选择不会持久化,并且静态UIElements会在已经使用时添加到某处时导致异常。
即使花了很多时间在这个问题上,我也不确定我做错了什么。使用模板选择器而不是当前选择正确视图的方式无效。
欢迎任何想法!
编辑1
有趣的是,我在这里躺着的AvalonDock版本有更好的结果。这是2016年某个时候的2.0.0版本,而不是当前版本的3.5.0。完全相同的代码可以像我期望的那样使用旧版本,而不是最新版本。
履行
下面是我对AvalonDock实现的略微缩写版本。
主要观点:
<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>
主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());
}));
}
工作区视图(请注意,在ListView中向下滚动时,离开选项卡并返回时,滚动位置将重置,导致重新创建视图):
<UserControl ...>
<Grid>
<ListView ItemsSource="{Binding Items}" />
</Grid>
</UserControl>
工作区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());
}
}
最后是抽象的WorkspaceBase类:
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()
{
}
}
似乎这是AvalonDock本身的一个问题。此版本的控件修复了所描述的问题:https://github.com/Dirkster99/AvalonDock。