在 WPF 行为中,是否可以添加不属于其附加控件的新事件,如果是,如何添加

本文关键字:添加 新事件 事件 如果 何添加 控件 WPF 是否 不属于 | 更新日期: 2023-09-27 18:33:49

我想向现有控件添加一个新事件。

我想向停靠控件添加新属性和事件。我有权访问返回当前活动窗口的事件"OnLastActiveDocumentChanged"。从该活动窗口中,我可以从其DataContext中检索我的活动视图模型。

我想添加一个属性"ActiveModel"和一个事件"OnActiveModelChanged"。

我目前使用该属性进行了行为,但不知道如何添加事件?

我可以在行为中添加事件以及如何添加吗?我想知道我是否写一个混合行为会更好?

来自ActiPro并由我修改的代码:

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Threading;
using ActiproSoftware.Windows.Controls.Docking;
// using ActiproSoftware.ProductSamples.DockingSamples.Common.ViewModels;
namespace ActiProUtil
{
    /// <summary>
    /// Provides attached behaviors for <see cref="DockSite"/> that properly initializes/opens windows associated with view-models.
    /// </summary>
    public static class DockSiteViewModelBehavior
    {
        #region Dependency Properties
        /// <summary>
        /// Identifies the <c>IsManaged</c> attached dependency property.  This field is read-only.
        /// </summary>
        /// <value>The identifier for the <c>IsManaged</c> attached dependency property.</value>
        public static readonly DependencyProperty IsManagedProperty = DependencyProperty.RegisterAttached("IsManaged",
            typeof(bool), typeof(DockSiteViewModelBehavior), new FrameworkPropertyMetadata(false, OnIsManagedPropertyValueChanged));
        /// <summary>
        /// Identifies the <c>WindowsPendingOpen</c> attached dependency property.  This field is read-only.
        /// </summary>
        /// <value>The identifier for the <c>WindowsPendingOpen</c> attached dependency property.</value>
        private static readonly DependencyProperty WindowsPendingOpenProperty = DependencyProperty.RegisterAttached("WindowsPendingOpen",
            typeof(IList<DockingWindow>), typeof(DockSiteViewModelBehavior), new FrameworkPropertyMetadata(null));
        public static readonly DependencyProperty ActiveModelProperty = DependencyProperty.RegisterAttached("ActiveModel",
            typeof (object), typeof (DockSiteViewModelBehavior)); //, new FrameworkPropertyMetadata(null, OnActiveModelChanged));
        //public static readonly RoutedEvent OnModelActiveChnagedEvent = EventManager.RegisterRoutedEvent(
        //  "OnModelActiveChanged", RoutingStrategy.Bubble, typeof (RoutedEventHandler), typeof (DockSiteViewModelBehavior));
        #endregion // Dependency Properties
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // NON-PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Gets the first <see cref="ToolWindow"/> associated with the specified dock group.
        /// </summary>
        /// <param name="dockSite">The dock site to search.</param>
        /// <param name="dockGroup">The dock group.</param>
        /// <returns>
        /// A <see cref="ToolWindow"/>; otherwise, <see langword="null"/>.
        /// </returns>
        private static ToolWindow GetToolWindow(DockSite dockSite, string dockGroup)
        {
            if (dockSite != null && !string.IsNullOrEmpty(dockGroup))
            {
                foreach (ToolWindow toolWindow in dockSite.ToolWindows)
                {
                    ToolItemViewModel toolItemViewModel = toolWindow.DataContext as ToolItemViewModel;
                    if (toolItemViewModel != null && toolItemViewModel.DockGroup == dockGroup)
                        return toolWindow;
                }
            }
            return null;
        }
        /// <summary>
        /// Handles the <c>Loaded</c> event of the <c>DockSite</c> control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
        private static void OnDockSiteLoaded(object sender, RoutedEventArgs e)
        {
            DockSite dockSite = sender as DockSite;
            if (dockSite == null)
                return;
            // Open any windows that were waiting for the DockSite to be loaded
            IList<DockingWindow> windowsPendingOpen = dockSite.GetValue(WindowsPendingOpenProperty) as IList<DockingWindow>;
            dockSite.ClearValue(WindowsPendingOpenProperty);
            if (windowsPendingOpen != null && windowsPendingOpen.Count != 0)
            {
                foreach (DockingWindow dockingWindow in windowsPendingOpen)
                    OpenDockingWindow(dockSite, dockingWindow);
            }
        }
        /// <summary>
        /// Handles the <c>WindowRegistered</c> event of the <c>DockSite</c> control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="DockingWindowEventArgs"/> instance containing the event data.</param>
        private static void OnDockSiteWindowRegistered(object sender, DockingWindowEventArgs e)
        {
            DockSite dockSite = sender as DockSite;
            if (dockSite == null)
                return;
            // Ensure the DockingWindow exists and is generated for an item
            DockingWindow dockingWindow = e.Window;
            if (dockingWindow == null || !dockingWindow.IsContainerForItem)
                return;
            // Pass down the name, if any as this cannot be done via a Style
            if (string.IsNullOrEmpty(dockingWindow.Name))
            {
                ViewModelBase viewModel = dockingWindow.DataContext as ViewModelBase;
                if (viewModel != null && !string.IsNullOrEmpty(viewModel.Name))
                    dockingWindow.Name = viewModel.Name;
            }
            // Open the DockingWindow, if it's not already open
            if (!dockingWindow.IsOpen)
            {
                if (!dockSite.IsLoaded)
                {
                    // Need to delay the opening until after the DockSite is loaded because it's content will not be loaded
                    IList<DockingWindow> windowsPendingOpen = dockSite.GetValue(WindowsPendingOpenProperty) as IList<DockingWindow>;
                    if (windowsPendingOpen == null)
                    {
                        windowsPendingOpen = new List<DockingWindow>();
                        dockSite.SetValue(WindowsPendingOpenProperty, windowsPendingOpen);
                    }
                    windowsPendingOpen.Add(dockingWindow);
                }
                else
                {
                    OpenDockingWindow(dockSite, dockingWindow);
                    // EO: To fix a bug in event "LastActiveDocument" which does not trig on initial window.
                    dockSite.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        if (dockSite.DocumentWindows.Count == 1)
                        {
                            dockingWindow.Activate();
                        }
                    }));
                }
            }
        }
        /// <summary>
        /// Handles the <c>WindowUnregistered</c> event of the <c>DockSite</c> control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="DockingWindowEventArgs"/> instance containing the event data.</param>
        private static void OnDockSiteWindowUnregistered(object sender, DockingWindowEventArgs e)
        {
            DockSite dockSite = sender as DockSite;
            if (dockSite == null)
                return;
            // Ensure the DockingWindow exists and is generated for an item
            DockingWindow dockingWindow = e.Window;
            if (dockingWindow == null || !dockingWindow.IsContainerForItem)
                return;
            // Need to remove the window from the list of windows that are waiting to be opened
            IList<DockingWindow> windowsPendingOpen = dockSite.GetValue(WindowsPendingOpenProperty) as IList<DockingWindow>;
            if (windowsPendingOpen != null)
            {
                int index = windowsPendingOpen.IndexOf(dockingWindow);
                if (index != -1)
                    windowsPendingOpen.RemoveAt(index);
            }
        }
        /// <summary>
        /// Called when <see cref="IsManagedProperty"/> is changed.
        /// </summary>
        /// <param name="d">The dependency object that was changed.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnIsManagedPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DockSite dockSite = d as DockSite;
            if (dockSite == null)
                return;
            // Add/Remove handlers for various events, which will allow us to open/position generated windows
            if ((bool)e.NewValue)
            {
                dockSite.Loaded += DockSiteViewModelBehavior.OnDockSiteLoaded;
                dockSite.WindowRegistered += DockSiteViewModelBehavior.OnDockSiteWindowRegistered;
                dockSite.WindowUnregistered += DockSiteViewModelBehavior.OnDockSiteWindowUnregistered;
                // EO 2014-12-10, Added next line
                dockSite.LastActiveDocumentChanged += dockSite_LastActiveDocumentChanged;
            }
            else
            {
                dockSite.Loaded -= DockSiteViewModelBehavior.OnDockSiteLoaded;
                dockSite.WindowRegistered -= DockSiteViewModelBehavior.OnDockSiteWindowRegistered;
                dockSite.WindowUnregistered -= DockSiteViewModelBehavior.OnDockSiteWindowUnregistered;
                // EO 2014-12-10, Added next line
                dockSite.LastActiveDocumentChanged -= dockSite_LastActiveDocumentChanged;
            }
        }
        /// <summary>
        /// Called when <see cref="IsManagedProperty"/> is changed.
        /// </summary>
        /// <param name="d">The dependency object that was changed.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnActiveModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DockSite dockSite = d as DockSite;
            if (dockSite == null)
                return;
            OnActiveModelChanged(d, e);
        }
        /// <summary>
        /// EO 2014-12-10, Added next event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void dockSite_LastActiveDocumentChanged(object sender, DockingWindowPropertyChangedRoutedEventArgs e)
        {
            var dockSite = sender as DockSite;
            if (dockSite != null)
            {
                if (dockSite.ActiveWindow != null)
                {
                    var obj = dockSite.ActiveWindow.DataContext as object;
                    if (obj != null)
                    {
                        dockSite.SetValue(ActiveModelProperty, obj);
                        return;
                    }
                }
                dockSite.SetValue(ActiveModelProperty, null);
            }
        }
        /// <summary>
        /// Opens the specified docking window.
        /// </summary>
        /// <param name="dockSite">The dock site that owns the docking window.</param>
        /// <param name="dockingWindow">The docking window to open.</param>
        private static void OpenDockingWindow(DockSite dockSite, DockingWindow dockingWindow)
        {
            if (!dockingWindow.IsOpen)
            {
                if (dockingWindow is DocumentWindow)
                    dockingWindow.Open();
                else
                {
                    ToolWindow toolWindow = dockingWindow as ToolWindow;
                    ToolItemViewModel toolItemViewModel = dockingWindow.DataContext as ToolItemViewModel;
                    if (toolWindow != null && toolItemViewModel != null)
                    {
                        // Look for a ToolWindow within the same group, if found then dock to that group, otherwise either dock or auto-hide the window
                        ToolWindow targetToolWindow = GetToolWindow(dockSite, toolItemViewModel.DockGroup);
                        if (targetToolWindow != null && targetToolWindow != toolWindow)
                            toolWindow.Dock(targetToolWindow, Direction.Content);
                        else if (toolItemViewModel.IsInitiallyAutoHidden)
                            toolWindow.AutoHide(toolItemViewModel.DefaultDock);
                        else
                            toolWindow.Dock(dockSite, toolItemViewModel.DefaultDock);
                    }
                    else
                    {
                        dockingWindow.Open();
                    }
                }
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Gets the value of the <see cref="IsManagedProperty"/> attached property for a specified <see cref="DockSite"/>.
        /// </summary>
        /// <param name="obj">The object to which the attached property is retrieved.</param>
        /// <returns>
        /// <c>true</c> if the specified <see cref="DockSite"/> is being managed; otherwise <c>false</c>.
        /// </returns>
        public static bool GetIsManaged(DockSite obj)
        {
            if (null == obj) throw new ArgumentNullException("obj");
            return (bool)obj.GetValue(DockSiteViewModelBehavior.IsManagedProperty);
        }
        /// <summary>
        /// Sets the value of the <see cref="IsManagedProperty"/> attached property to a specified <see cref="DockSite"/>.
        /// </summary>
        /// <param name="obj">The object to which the attached property is written.</param>
        /// <param name="value">
        /// A value indicating whether the specified <see cref="DockSite"/> is being managed.
        /// </param>
        public static void SetIsManaged(DockSite obj, bool value)
        {
            if (null == obj) throw new ArgumentNullException("obj");
            obj.SetValue(DockSiteViewModelBehavior.IsManagedProperty, value);
        }
    }
}

XAML:

<docking:DockSite x:Name="DockSiteMain" 
    CanToolWindowsBecomeDocuments="False"
    CanDocumentWindowsRaft="True"
    ItemContainerRetentionMode="Wrapped"
    actiProUtil:DockSiteViewModelBehavior.IsManaged="true"
    DocumentItemsSource="{Binding UserControlSvgEdits}" 
    DocumentItemContainerStyle="{StaticResource DocumentItemStyle}"
        >

在 WPF 行为中,是否可以添加不属于其附加控件的新事件,如果是,如何添加

为了从行为中添加其他事件,您应该使用附加事件。查看: 附加事件概述

代码应该是这样的:

public static class DockSiteViewModelBehavior
{
    ... 
    public static readonly RoutedEvent OnModelActiveChnagedEvent = EventManager.RegisterRoutedEvent(
      "OnModelActiveChanged", RoutingStrategy.Bubble, typeof (RoutedEventHandler), typeof (DockSiteViewModelBehavior));
    public static void AddOnModelActiveChangedHandler(DependencyObject d, RoutedEventHandler handler)
    {
        UIElement uie = d as UIElement;
        if (uie != null)
        {
            uie.AddHandler(OnModelActiveChnagedEvent, handler);
        }
    }
    public static void RemoveOnModelActiveChangedHandler(DependencyObject d, RoutedEventHandler handler)
    {
        UIElement uie = d as UIElement;
        if (uie != null)
        {
            uie.RemoveHandler(OnModelActiveChnagedEvent, handler);
        }
    }
    ...
    private static void OnActiveModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DockSite dockSite = d as DockSite;
        if (dockSite == null)
            return;
        dockSite.RaiseEvent(new RoutedEventArgs(OnModelActiveChnagedEvent, dockSite));
    }
}

我把我的行为更改为较新的行为架构(System.Windows.Interactivity中定义的"blend"样式)。然后我只在我的行为中添加了一个常规事件,该事件按预期工作。

有代码:行为及其在xaml中的调用:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Threading;
using ActiproSoftware.Windows.Controls.Docking;
// using ActiproSoftware.ProductSamples.DockingSamples.Common.ViewModels;
namespace ActiProUtil
{
    public delegate void ActiveModelChangedHandler(object sender, DependencyPropertyChangedEventArgs eventArgs);
    /// <summary>
    /// EO: Provides attached behaviors for <see cref="DockSite"/> that properly initializes/opens windows associated
    /// with view-models. Proper behavior depends on the Model staying the DataContext of the view
    /// </summary>
    public class DockSiteViewModelBehavior : Behavior<DockSite>
    {
        // ******************************************************************
        /// <summary>
        /// Identifies the <c>IsManaged</c> attached dependency property.  This field is read-only.
        /// </summary>
        /// <value>The identifier for the <c>IsManaged</c> attached dependency property.</value>
        public static readonly DependencyProperty IsManagedProperty = DependencyProperty.Register("IsManaged",
            typeof(bool), typeof(DockSiteViewModelBehavior), new FrameworkPropertyMetadata(false, OnIsManagedPropertyValueChanged));
        /// <summary>
        /// Identifies the <c>WindowsPendingOpen</c> attached dependency property.  This field is read-only.
        /// </summary>
        /// <value>The identifier for the <c>WindowsPendingOpen</c> attached dependency property.</value>
        private static readonly DependencyProperty WindowsPendingOpenProperty = DependencyProperty.Register("WindowsPendingOpen",
            typeof(IList<DockingWindow>), typeof(DockSiteViewModelBehavior), new FrameworkPropertyMetadata(null));
        public static readonly DependencyProperty ActiveModelProperty = DependencyProperty.Register("ActiveModel",
            typeof (object), typeof (DockSiteViewModelBehavior), new FrameworkPropertyMetadata(null, OnActiveModelChanged));
        //public static readonly RoutedEvent OnModelActiveChnagedEvent = EventManager.RegisterRoutedEvent(
        //  "OnModelActiveChanged", RoutingStrategy.Bubble, typeof (RoutedEventHandler), typeof (DockSiteViewModelBehavior));
        public static readonly DependencyProperty ModelsSourceProperty = DependencyProperty.Register("ModelsSource",
            typeof(object), typeof(DockSiteViewModelBehavior), new FrameworkPropertyMetadata(null, OnDocumentSourceChanged));
        public event ActiveModelChangedHandler ActiveModelChanged;
        // ******************************************************************
        private DockSite _dockSite = null;
        // ******************************************************************
        private DockSite DockSite
        {
            get
            {
                if (_dockSite == null)
                {
                    _dockSite = AssociatedObject;
                }
                return _dockSite;
            }
        }
        // ******************************************************************
        /// <summary>
        /// Gets the first <see cref="ToolWindow"/> associated with the specified dock group.
        /// </summary>
        /// <param name="dockSite">The dock site to search.</param>
        /// <param name="dockGroup">The dock group.</param>
        /// <returns>
        /// A <see cref="ToolWindow"/>; otherwise, <see langword="null"/>.
        /// </returns>
        private static ToolWindow GetToolWindow(DockSite dockSite, string dockGroup)
        {
            if (dockSite != null && !string.IsNullOrEmpty(dockGroup))
            {
                foreach (ToolWindow toolWindow in dockSite.ToolWindows)
                {
                    ToolItemViewModel toolItemViewModel = toolWindow.DataContext as ToolItemViewModel;
                    if (toolItemViewModel != null && toolItemViewModel.DockGroup == dockGroup)
                        return toolWindow;
                }
            }
            return null;
        }
        // ******************************************************************
        /// <summary>
        /// Handles the <c>Loaded</c> event of the <c>DockSite</c> control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
        private void OnDockSiteLoaded(object sender, RoutedEventArgs e)
        {
            // Open any windows that were waiting for the DockSite to be loaded
            IList<DockingWindow> windowsPendingOpen = DockSite.GetValue(WindowsPendingOpenProperty) as IList<DockingWindow>;
            DockSite.ClearValue(WindowsPendingOpenProperty);
            if (windowsPendingOpen != null && windowsPendingOpen.Count != 0)
            {
                foreach (DockingWindow dockingWindow in windowsPendingOpen)
                    OpenDockingWindow(DockSite, dockingWindow);
            }
        }
        // ******************************************************************
        /// <summary>
        /// Handles the <c>WindowRegistered</c> event of the <c>DockSite</c> control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="DockingWindowEventArgs"/> instance containing the event data.</param>
        private void OnDockSiteWindowRegistered(object sender, DockingWindowEventArgs e)
        {
            var dockSite = sender as DockSite;
            if (dockSite == null)
                throw new ArgumentException("DockSiteViewModelBehavior is dedicated to actipro DockSite");
            // Ensure the DockingWindow exists and is generated for an item
            DockingWindow dockingWindow = e.Window;
            if (dockingWindow == null || !dockingWindow.IsContainerForItem)
                return;
            // Pass down the name, if any as this cannot be done via a Style
            if (string.IsNullOrEmpty(dockingWindow.Name))
            {
                ViewModelBase viewModel = dockingWindow.DataContext as ViewModelBase;
                if (viewModel != null && !string.IsNullOrEmpty(viewModel.Name))
                    dockingWindow.Name = viewModel.Name;
            }
            // Open the DockingWindow, if it's not already open
            if (!dockingWindow.IsOpen)
            {
                if (!dockSite.IsLoaded)
                {
                    // Need to delay the opening until after the DockSite is loaded because it's content will not be loaded
                    IList<DockingWindow> windowsPendingOpen = dockSite.GetValue(WindowsPendingOpenProperty) as IList<DockingWindow>;
                    if (windowsPendingOpen == null)
                    {
                        windowsPendingOpen = new List<DockingWindow>();
                        dockSite.SetValue(WindowsPendingOpenProperty, windowsPendingOpen);
                    }
                    windowsPendingOpen.Add(dockingWindow);
                }
                else
                {
                    OpenDockingWindow(dockSite, dockingWindow);
                    // EO: To fix a bug in event "LastActiveDocument" which does not trig on initial window.
                    dockSite.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        if (dockSite.DocumentWindows.Count == 1)
                        {
                            dockingWindow.Activate();
                        }
                    }), DispatcherPriority.ContextIdle);
                }
            }
        }
        // ******************************************************************
        private void EnsureDockingWindowAssociatedModelIsClose(DockingWindow dockingWindow)
        {
            if (dockingWindow != null)
            {
                object model = GetDockinWindowDataContext(dockingWindow);
                if (model != null)
                {
                    var iList = ModelsSource as IList;
                    if (iList != null)
                    {
                        iList.Remove(model);
                    }
                }
            }
        }
        // ******************************************************************
        /// <summary>
        /// Handles the <c>WindowUnregistered</c> event of the <c>DockSite</c> control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="DockingWindowEventArgs"/> instance containing the event data.</param>
        private void OnDockSiteWindowUnregistered(object sender, DockingWindowEventArgs e)
        {
            DockSite dockSite = sender as DockSite;
            if (dockSite == null)
                return;
            // Ensure the DockingWindow exists and is generated for an item
            DockingWindow dockingWindow = e.Window;
            if (dockingWindow == null || !dockingWindow.IsContainerForItem)
                return;
            // Need to remove the window from the list of windows that are waiting to be opened
            IList<DockingWindow> windowsPendingOpen = dockSite.GetValue(WindowsPendingOpenProperty) as IList<DockingWindow>;
            if (windowsPendingOpen != null)
            {
                int index = windowsPendingOpen.IndexOf(dockingWindow);
                if (index != -1)
                {
                    EnsureDockingWindowAssociatedModelIsClose(dockingWindow);
                    windowsPendingOpen.RemoveAt(index);
                }
            }
        }
        // ******************************************************************
        /// <summary>
        /// Called when <see cref="IsManagedProperty"/> is changed.
        /// </summary>
        /// <param name="d">The dependency object that was changed.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnIsManagedPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var dockSiteViewModelBehavior = d as DockSiteViewModelBehavior;
            if (dockSiteViewModelBehavior == null)
            {
                return;
            }
        }
        // ******************************************************************
        protected override void OnAttached()
        {
            base.OnAttached();
            var dockSite = DockSite;
            // Add/Remove handlers for various events, which will allow us to open/position generated windows
            if (IsManaged)
            {
                dockSite.Loaded += OnDockSiteLoaded;
                dockSite.WindowRegistered += OnDockSiteWindowRegistered;
                dockSite.WindowUnregistered += OnDockSiteWindowUnregistered;

                // EO 2014-12-10, Added next lines
                dockSite.WindowClosing += dockSite_WindowClosing;
                dockSite.LastActiveDocumentChanged += DockSiteOnLastActiveDocumentChanged;
            }
            else
            {
                dockSite.Loaded -= OnDockSiteLoaded;
                dockSite.WindowRegistered -= OnDockSiteWindowRegistered;
                dockSite.WindowUnregistered -= OnDockSiteWindowUnregistered;
                // EO 2014-12-10, Added next lines
                dockSite.WindowClosing -= dockSite_WindowClosing;
                dockSite.LastActiveDocumentChanged -= DockSiteOnLastActiveDocumentChanged;
            }
        }
        // ******************************************************************
        void dockSite_WindowClosing(object sender, DockingWindowEventArgs e)
        {
            EnsureDockingWindowAssociatedModelIsClose(e.Window);
        }
        // ******************************************************************
        private void DockSiteOnLastActiveDocumentChanged(object sender, DockingWindowPropertyChangedRoutedEventArgs dockingWindowPropertyChangedRoutedEventArgs)
        {
            var dockSite = sender as DockSite;
            if (dockSite != null)
            {
                if (dockSite.ActiveWindow != null)
                {
                    var frameWorkElement = dockSite.ActiveWindow.Content as FrameworkElement;
                    if (frameWorkElement != null)
                    {
                        ActiveModel = frameWorkElement.DataContext;
                        return;
                    }
                }
                ActiveModel = null;
            }
        }
        // ******************************************************************
        /// <summary>
        /// Called when <see cref="IsManagedProperty"/> is changed.
        /// </summary>
        /// <param name="d">The dependency object that was changed.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnDocumentSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var behavior = d as DockSiteViewModelBehavior;
            if (behavior == null)
            {
                throw new ArgumentNullException();              
            }
            var obsCollOld = e.OldValue as INotifyCollectionChanged;
            if (obsCollOld != null)
            {
                obsCollOld.CollectionChanged -= behavior.ObjCollCollectionChanged;
            }
            var obsCollNew = e.NewValue as INotifyCollectionChanged;
            if (obsCollNew != null)
            {
                obsCollNew.CollectionChanged += behavior.ObjCollCollectionChanged;
            }
        }
        // ******************************************************************
        void ObjCollCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            // Find the DataTemplate
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                foreach (object obj in e.NewItems)
                {
                    // Here th obj Type is the key to the resource, it works but
                    var key = new System.Windows.DataTemplateKey(obj.GetType());
                    var dataTemplate = (DataTemplate)DockSite.FindResource(key);
                    var userControl = dataTemplate.LoadContent() as UserControl;
                    if (userControl != null)
                    {
                        userControl.DataContext = obj;
                        var documentWindow = new DocumentWindow(DockSite, null, "Title from viemodel", null, userControl);
                        documentWindow.Description = "viewModel.Description";
                        // Activate the document
                        documentWindow.Activate();
                    }
                }
            }
        }
        // ******************************************************************
        /// <summary>
        /// Called when <see cref="IsManagedProperty"/> is changed.
        /// </summary>
        /// <param name="d">The dependency object that was changed.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnActiveModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var behavior = d as DockSiteViewModelBehavior;
            if (behavior == null)
            {
                return;
            }
            DockSite dockSite = behavior.AssociatedObject;
            bool isAlreadyProperModelOfProperActiveWindow = false;
            if (dockSite.ActiveWindow != null)
            {
                var frameworkElement = dockSite.ActiveWindow.Content as FrameworkElement;
                if (frameworkElement != null)
                {
                    if (frameworkElement.DataContext == behavior.ActiveModel)
                    {
                        isAlreadyProperModelOfProperActiveWindow = true;
                    }
                }
            }
            if (!isAlreadyProperModelOfProperActiveWindow)
            {
                foreach (var docWin in dockSite.DocumentWindows)
                {
                    var frameworkElement = docWin.Content as FrameworkElement;
                    if (frameworkElement != null)
                    {
                        if (frameworkElement.DataContext == behavior.ActiveModel)
                        {
                            docWin.Activate();
                        }
                    }
                }
            }
            if (behavior.ActiveModelChanged != null)
            {
                behavior.ActiveModelChanged(behavior, new DependencyPropertyChangedEventArgs(ActiveModelProperty, e.OldValue, e.NewValue));
            }
        }
        // ******************************************************************
        /// <summary>
        /// Opens the specified docking window.
        /// </summary>
        /// <param name="dockSite">The dock site that owns the docking window.</param>
        /// <param name="dockingWindow">The docking window to open.</param>
        private static void OpenDockingWindow(DockSite dockSite, DockingWindow dockingWindow)
        {
            if (!dockingWindow.IsOpen)
            {
                if (dockingWindow is DocumentWindow)
                    dockingWindow.Open();
                else
                {
                    ToolWindow toolWindow = dockingWindow as ToolWindow;
                    ToolItemViewModel toolItemViewModel = dockingWindow.DataContext as ToolItemViewModel;
                    if (toolWindow != null && toolItemViewModel != null)
                    {
                        // Look for a ToolWindow within the same group, if found then dock to that group, otherwise either dock or auto-hide the window
                        ToolWindow targetToolWindow = GetToolWindow(dockSite, toolItemViewModel.DockGroup);
                        if (targetToolWindow != null && targetToolWindow != toolWindow)
                            toolWindow.Dock(targetToolWindow, Direction.Content);
                        else if (toolItemViewModel.IsInitiallyAutoHidden)
                            toolWindow.AutoHide(toolItemViewModel.DefaultDock);
                        else
                            toolWindow.Dock(dockSite, toolItemViewModel.DefaultDock);
                    }
                    else
                    {
                        dockingWindow.Open();
                    }
                }
            }
        }
        // ******************************************************************
        public bool IsManaged
        {
            get { return (bool)GetValue(DockSiteViewModelBehavior.IsManagedProperty); }
            set { SetValue(DockSiteViewModelBehavior.IsManagedProperty, value); }
        }
        // ******************************************************************
        public object ModelsSource
        {
            get { return GetValue(ModelsSourceProperty); }
            set { SetValue(ModelsSourceProperty, value); }
        }
        // ******************************************************************
        public object ActiveModel
        {
            get { return GetValue(ActiveModelProperty); }
            set { SetValue(ActiveModelProperty, value); }
        }
        // ******************************************************************
        private static object GetDockinWindowDataContext(DockingWindow dockingWindow)
        {
            object dataContext = null;
            if (dockingWindow != null)
            {
                var frameworkElement = dockingWindow.Content as FrameworkElement;
                if (frameworkElement != null)
                {
                    dataContext = frameworkElement.DataContext;
                }
            }
            return dataContext;
        }
        // ******************************************************************
    }
}

这是使用以下行为的 xaml 部分:

        <docking:DockSite x:Name="DockSiteMain" 
            CanToolWindowsBecomeDocuments="False"
            CanDocumentWindowsRaft="True"
            ItemContainerRetentionMode="Wrapped"
            >
            <i:Interaction.Behaviors>
                <actiProUtil:DockSiteViewModelBehavior 
                    IsManaged="true"
                    ModelsSource = "{Binding UserControlSvgEditModels}"
                    ActiveModel ="{Binding ActiveModel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                    ActiveModelChanged="DockSiteViewModelBehaviorOnActiveModelChanged"
                    >
                </actiProUtil:DockSiteViewModelBehavior>
            </i:Interaction.Behaviors>
...