如何自动将布局加载到我的 AvalonDock 实例中
本文关键字:我的 AvalonDock 实例 加载 何自动 布局 | 更新日期: 2023-09-27 17:56:26
我已经将AvalonDock 2.0集成到我的应用程序中。我已经将文档和可锚定的源绑定到我的视图模型,这些视图模型通过DataTemplate
使用正确的用户控件呈现。
我可以使用XmlLayoutSerializer
加载和保存布局。我需要支持按需加载预定义的布局(通过 Button
s 和 ICommand
s)。那也行得通。
我无法开始的工作是在DockingManager
完成加载视图模型及其视图(用户控件)时自动加载序列化布局。
我尝试在DockingManager.DataContextChanged
上加载我的布局,但我认为它触发得太早了,因为布局加载了隐藏部分中的文档和可见部分中的重复文档。呈现的窗格不反映加载的布局,当再次保存布局时,重复项将累积在隐藏部分中。
<ad:DockingManager Name="DockingManager"
DataContext="{Binding Project}"
DataContextChanged="DockingManager_OnDataContextChanged"
ActiveContent="{Binding Active}"
AnchorablesSource="{Binding Anchorables}"
DocumentsSource="{Binding Documents}">
<ad:DockingManager.Theme>
<ad:AeroTheme/>
</ad:DockingManager.Theme>
<ad:DockingManager.LayoutItemTemplateSelector>
<views:PanesTemplateSelector>
<views:PanesTemplateSelector.ChartTemplate>
<DataTemplate>
<views:Chart/>
</DataTemplate>
</views:PanesTemplateSelector.ChartTemplate>
<views:PanesTemplateSelector.WorkspaceTemplate>
<DataTemplate>
<Views:Workspace/>
</DataTemplate>
</views:PanesTemplateSelector.WorkspaceTemplate>
...
</views:PanesTemplateSelector>
</ad:DockingManager.LayoutItemTemplateSelector>
<ad:DockingManager.LayoutItemContainerStyle>
<Style TargetType="{x:Type ad:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.DisplayText}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
</Style>
</ad:DockingManager.LayoutItemContainerStyle>
<ad:LayoutRoot>
<!--<ad:LayoutPanel>
<ad:LayoutDocumentPane/>
<ad:LayoutAnchorablePane/>
</ad:LayoutPanel>-->
</ad:LayoutRoot>
</ad:DockingManager>
。和代码隐藏...
private void SaveLayout() {
if (this.DataContext == null)
return;
var xmlLayoutSerializer = new XmlLayoutSerializer(this.DockingManager);
var stringBuilder = new StringBuilder();
using (var textWriter = new StringWriter(stringBuilder))
xmlLayoutSerializer.Serialize(textWriter);
var serialized = stringBuilder.ToString();
(this.DataContext as dynamic).XmlSerializedAndEscapedLayout = HttpUtility.HtmlEncode(serialized);
}
private void LoadLayout()
{
if (DataContext == null)
return;
var encoded = (DataContext as dynamic).XmlSerializedAndEscapedLayout;
var window = Window.GetWindow(this);
window.Closing += (sender, args) => SaveLayout();
if (String.IsNullOrWhiteSpace(encoded))
return;
var serialized = HttpUtility.HtmlDecode(encoded);
var xmlLayoutSerializer = new XmlLayoutSerializer(DockingManager);
using (var stringReader = new StringReader(serialized))
xmlLayoutSerializer.Deserialize(stringReader);
}
private void DockingManager_OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != null) // A type check here would be best, I know.
LoadLayout();
}
。和视图模型...
public class ProjectViewModel
{
public IModel Model { get; private set; }
public String SerializedLayout { get; set; }
public ViewModelBase Active { get; set; }
private readonly ObservableCollection<ViewModelBase> documents;
public ReadOnlyObservableCollection<ViewModelBase> Documents { get; private set; }
private readonly ObservableCollection<ViewModelBase> anchorables;
public ReadOnlyObservableCollection<ViewModelBase> Anchorables { get; private set; }
public ProjectViewModel(String filePath, String serializedLayout)
{
SerializedLayout = serializedLayout;
using (var fileStream = new FileStream(filePath, FileMode.Open))
{
IModelRepository modelRepository = Ioc.DependencyInjectionContainer.DefaultContainer.Resolve<IModelRepository>();
Model = modelRepository.Load(fileStream);
}
documents = new ObservableCollection<ViewModelBase>();
anchorables = new ObservableCollection<ViewModelBase>();
documents.Add(new Workspace());
anchorables.Add(new RiskLimitsViewModel(Model.RiskLimits));
...
Documents = new ReadOnlyObservableCollection<ViewModelBase>(documents);
Anchorables = new ReadOnlyObservableCollection<ViewModelBase>(anchorables);
}
}
任何见解将不胜感激。谢谢!
我不得不在 XAML 中添加这个......
...
</ad:DockingManager.Theme>
<ad:DockingManager.LayoutUpdateStrategy>
<views:LayoutUpdateStrategy/>
</ad:DockingManager.LayoutUpdateStrategy>
<ad:DockingManager.LayoutItemTemplateSelector>
...
。这在代码隐藏中...
class LayoutUpdateStrategy : ILayoutUpdateStrategy
{
private bool BeforeInsertContent(LayoutRoot layout, LayoutContent anchorableToShow)
{
var viewModel = (ViewModelBase) anchorableToShow.Content;
var layoutContent = layout.Descendents().OfType<LayoutContent>().FirstOrDefault(x => x.ContentId == viewModel.ContentId);
if (layoutContent == null)
return false;
layoutContent.Content = anchorableToShow.Content;
// Add layoutContent to it's previous container
var layoutContainer = layoutContent.GetType().GetProperty("PreviousContainer", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(layoutContent, null) as ILayoutContainer;
if (layoutContainer is LayoutAnchorablePane)
(layoutContainer as LayoutAnchorablePane).Children.Add(layoutContent as LayoutAnchorable);
else if (layoutContainer is LayoutDocumentPane)
(layoutContainer as LayoutDocumentPane).Children.Add(layoutContent);
else
throw new NotSupportedException();
return true;
}
public bool BeforeInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableToShow, ILayoutContainer destinationContainer)
{
return BeforeInsertContent(layout, anchorableToShow);
}
public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown) {}
public bool BeforeInsertDocument(LayoutRoot layout, LayoutDocument anchorableToShow, ILayoutContainer destinationContainer)
{
return BeforeInsertContent(layout, anchorableToShow);
}
public void AfterInsertDocument(LayoutRoot layout, LayoutDocument anchorableShown) {}
}
我用了这个:
XAML:
<avalonDock:DockingManager
x:Name="dockManager"
AllowMixedOrientation="True"
DocumentClosing="dockManager_DocumentClosing"
AnchorablesSource="{Binding ListUserPanelAnchorable}"
DocumentsSource="{Binding ListUserPanel}"
Theme="{Binding avalondockTheme}">
型:
public ObservableCollection<UserPanel> _ListUserPanelAnchorable;
ReadOnlyObservableCollection<UserPanel> _readonyFiles = null;
public ReadOnlyObservableCollection<UserPanel> ListUserPanelAnchorable
{
get
{
if (_readonyFiles == null)
_readonyFiles = new ReadOnlyObservableCollection<UserPanel>(_ListUserPanelAnchorable);
return _readonyFiles;
}
}
XAML.cs:
private void loadLayout()
{
//dockPanelModel.ListUserPanel.Clear();
//dockPanelModel.ListUserPanelAnchorable.Clear();
var serializer = new XmlLayoutSerializer(dockManager);
serializer = new XmlLayoutSerializer(dockManager);
serializer.LayoutSerializationCallback += (s, args) =>
{
args.Content = userPanel;
dockPanelModel._ListUserPanelAnchorable.Add(userPanel);
}
}
public AvaladonDockPanel()
{
InitializeComponent();
this.Loaded += AvaladonDockPanel_Loaded;
}
void AvaladonDockPanel_Loaded(object sender, RoutedEventArgs e)
{
loadLayout();
}
用户面板:
public class UserPanel
{
public string Title { get; set; }
public string ToolTip { get; set; }
public string IconSource { get; set; }
private Guid _contentGuid = Guid.NewGuid();
public Guid ContentId
{
get { return _contentGuid; }
set { _contentGuid = value; }
}
private UserControl _UserInterface;
public UserControl UserInterface { get { return _UserInterface; } set { _UserInterface = value; NotifyPropertyChanged("UserInterface"); } }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
Debug.WriteLine(string.Format("PropertyChanged-> {0}", propertyName));
}
}
}
将 Avalon 绑定到用户面板:
<avalonDock:DockingManager.LayoutItemContainerStyle>
<Style TargetType="{x:Type avalonDock:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
<Setter Property="ToolTip" Value="{Binding Model.ToolTip}"/>
<Setter Property="IconSource" Value="{Binding Model.IconSource}" />
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
</Style>
</avalonDock:DockingManager.LayoutItemContainerStyle>
<avalonDock:DockingManager.LayoutItemTemplate >
<DataTemplate >
<ContentPresenter Content="{Binding UserInterface}" />
</DataTemplate>
</avalonDock:DockingManager.LayoutItemTemplate>