【问题标题】:C# Prism Сommunication between AvalonDock and MainApplicationViewAvalonDock 和 MainApplicationView 之间的 C# Prism 通信
【发布时间】:2021-01-15 13:35:34
【问题描述】:

我正在尝试弄清楚如何在 Prism 中使用 AvalonDock。我的 MainApplciationView Xaml 代码:

<Window x:Class="WPFTestLab.Views.ApplicationWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:fa="http://schemas.fontawesome.com/icons/"
    xmlns:prism="http://prismlibrary.com/"
    prism:ViewModelLocator.AutoWireViewModel="True"
    xmlns:core="clr-namespace:WPFTestLab.Core;assembly=WPFTestLab.Core"  
    xmlns:avalonDock="https://github.com/Dirkster99/AvalonDock"
    Title="{Binding Title}" Width="1280" Height="720" WindowStartupLocation="CenterScreen">
<Grid>
    <avalonDock:DockingManager prism:RegionManager.RegionName="{x:Static core:RegionNames.MainRegion}">
        <avalonDock:LayoutRoot>
            <avalonDock:LayoutPanel Orientation="Horizontal">
                <avalonDock:LayoutDocumentPaneGroup DockWidth="100" Orientation="Vertical">
                    <avalonDock:LayoutDocumentPane>

                    </avalonDock:LayoutDocumentPane>
                </avalonDock:LayoutDocumentPaneGroup>
            </avalonDock:LayoutPanel>
        </avalonDock:LayoutRoot>
    </avalonDock:DockingManager>
</Grid>

我创建了对接管理器区域适配器:

public class AvalonDockingRegionAdapter : RegionAdapterBase<DockingManager>
{
    private bool _updatingActiveViewsInManagerActiveContentChanged;
    #region Constructor

    public AvalonDockingRegionAdapter(IRegionBehaviorFactory factory)
        : base(factory)
    {
        _updatingActiveViewsInManagerActiveContentChanged = false;
    }

    #endregion  //Constructor


    #region Overrides

    protected override IRegion CreateRegion()
    {
        return new SingleActiveRegion();
    }

    protected override void Adapt(IRegion region, DockingManager regionTarget)
    {
        regionTarget.ActiveContentChanged += delegate (
            object sender, EventArgs e)
        {
            this.ManagerActiveContentChanged(sender, e, region, regionTarget);
        };
        region.Views.CollectionChanged += delegate (
            Object sender, NotifyCollectionChangedEventArgs e)
        {
            this.OnViewsCollectionChanged(sender, e, region, regionTarget);
        };
        region.Views.CollectionChanged += delegate (
            Object sender, NotifyCollectionChangedEventArgs e)
        {
            this.OnActiveViewsCollectionChanged(sender, e, region, regionTarget);
        };
        regionTarget.DocumentClosed += delegate (
                        Object sender, DocumentClosedEventArgs e)
        {
            this.OnDocumentClosedEventArgs(sender, e, region);
        };
    }

    private void OnActiveViewsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e, IRegion region, DockingManager regionTarget)
    {
        if (_updatingActiveViewsInManagerActiveContentChanged) return;

        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            if (regionTarget.ActiveContent != null && regionTarget.ActiveContent != e.NewItems[0] &&
                region.ActiveViews.Contains(regionTarget.ActiveContent))
                region.Deactivate(regionTarget.ActiveContent);

            regionTarget.ActiveContent = e.NewItems[0];
        }
        else if (e.Action == NotifyCollectionChangedAction.Remove &&
                 e.OldItems.Contains(regionTarget.ActiveContent))
        {
            regionTarget.ActiveContent = null;
        }
    }

    private void ManagerActiveContentChanged(object sender, EventArgs e, IRegion region, DockingManager regionTarget)
    {
        try
        {
            _updatingActiveViewsInManagerActiveContentChanged = true;

            if (regionTarget == sender)
            {
                var activeContent = regionTarget.ActiveContent;
                if (activeContent != null)
                {
                    foreach (var item in region.ActiveViews.Where(it => it != activeContent))
                        if (region.Views.Contains(item))
                            region.Deactivate(item);

                    if (region.Views.Contains(activeContent) && !region.ActiveViews.Contains(activeContent))
                        region.Activate(activeContent);
                }
            }
        }
        finally
        {
            _updatingActiveViewsInManagerActiveContentChanged = false;
        }

    }

    #endregion  //Overrides


    #region Event Handlers

    /// <summary>
    /// Handles the NotifyCollectionChangedEventArgs event.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The event.</param>
    /// <param name="region">The region.</param>
    /// <param name="regionTarget">The region target.</param>
    void OnViewsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e, IRegion region, DockingManager regionTarget)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            foreach (FrameworkElement item in e.NewItems)
            {
                UIElement view = item as UIElement;

                if (view != null)
                {
                    //Create a new layout document to be included in the LayoutDocuemntPane (defined in xaml)
                    LayoutDocument newLayoutDocument = new LayoutDocument();
                    newLayoutDocument.Content = item;

                    PaneViewModel viewModel = (PaneViewModel)item.DataContext;

                    if (viewModel != null)
                        newLayoutDocument.Title = viewModel.Title;

                    //Store all LayoutDocuments already pertaining to the LayoutDocumentPane (defined in xaml)
                    List<LayoutDocument> oldLayoutDocuments = new List<LayoutDocument>();
                    //Get the current ILayoutDocumentPane ... Depending on the arrangement of the views this can be either 
                    //a simple LayoutDocumentPane or a LayoutDocumentPaneGroup
                    ILayoutDocumentPane currentILayoutDocumentPane = (ILayoutDocumentPane)regionTarget.Layout.RootPanel.Children[0];

                    if (currentILayoutDocumentPane.GetType() == typeof(LayoutDocumentPaneGroup))
                    {
                        //If the current ILayoutDocumentPane turns out to be a group
                        //Get the children (LayoutDocuments) of the first pane
                        LayoutDocumentPane oldLayoutDocumentPane = (LayoutDocumentPane)currentILayoutDocumentPane.Children.ToList()[0];
                        foreach (LayoutDocument child in oldLayoutDocumentPane.Children)
                        {
                            oldLayoutDocuments.Insert(0, child);
                        }
                    }
                    else if (currentILayoutDocumentPane.GetType() == typeof(LayoutDocumentPane))
                    {
                        //If the current ILayoutDocumentPane turns out to be a simple pane
                        //Get the children (LayoutDocuments) of the single existing pane.
                        foreach (LayoutDocument child in currentILayoutDocumentPane.Children)
                        {
                            oldLayoutDocuments.Insert(0, child);
                        }
                    }

                    //Create a new LayoutDocumentPane and inserts your new LayoutDocument
                    LayoutDocumentPane newLayoutDocumentPane = new LayoutDocumentPane();
                    newLayoutDocumentPane.InsertChildAt(0, newLayoutDocument);

                    //Append to the new LayoutDocumentPane the old LayoutDocuments
                    foreach (LayoutDocument doc in oldLayoutDocuments)
                    {
                        newLayoutDocumentPane.InsertChildAt(0, doc);
                    }

                    //Traverse the visual tree of the xaml and replace the LayoutDocumentPane (or LayoutDocumentPaneGroup) in xaml
                    //with your new LayoutDocumentPane (or LayoutDocumentPaneGroup)
                    if (currentILayoutDocumentPane.GetType() == typeof(LayoutDocumentPane))
                        regionTarget.Layout.RootPanel.ReplaceChildAt(0, newLayoutDocumentPane);
                    else if (currentILayoutDocumentPane.GetType() == typeof(LayoutDocumentPaneGroup))
                    {
                        currentILayoutDocumentPane.ReplaceChild(currentILayoutDocumentPane.Children.ToList()[0], newLayoutDocumentPane);
                        regionTarget.Layout.RootPanel.ReplaceChildAt(0, currentILayoutDocumentPane);
                    }
                    newLayoutDocument.IsActive = true;
                }
            }
        }
    }

    /// <summary>
    /// Handles the DocumentClosedEventArgs event raised by the DockingNanager when
    /// one of the LayoutContent it hosts is closed.
    /// </summary>
    /// <param name="sender">The sender</param>
    /// <param name="e">The event.</param>
    /// <param name="region">The region.</param>
    void OnDocumentClosedEventArgs(object sender, DocumentClosedEventArgs e, IRegion region)
    {
        region.Remove(e.Document.Content);
    }

    #endregion
}

我的问题是如何从 MainApplicationViewModel 操作停靠管理器。例如,我想捕捉 MainApplicationView 中的活动文档内容更改和禁用按钮。或者单击 MainApplicationView 中的按钮应该会更改当前活动文档视图中的文本。

【问题讨论】:

    标签: prism avalondock


    【解决方案1】:

    希望DockingManager 具有可以绑定到ApplicationWindowViewModel 上的内容的属性和命令。

    如果没有,您必须诉诸EventToCommand 和附加行为。

    从那以后,一切都是标准的。文档获取处于活动状态,文档视图模型的IsActive 属性变为真,通知服务,侦听服务的另一个视图模型意识到更改,文本更改...

    【讨论】:

      猜你喜欢
      • 2023-03-17
      • 2017-08-13
      • 2013-10-18
      • 2011-08-08
      • 2016-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多