【问题标题】:Activate DevExpress DocumentPanel in DocumentGroup region when Navigating with PRISM使用 PRISM 导航时激活 DocumentGroup 区域中的 DevExpress DocumentPanel
【发布时间】:2016-11-29 21:54:03
【问题描述】:

我正在使用 DevExpress 的 DocumentGroup 和 DocumentGroupAdapter(在他们网站上的 E3339 中描述)用于带有 PRISM 6 的 WPF 应用程序。我正在使用范围区域和 INavigationAware,一切都按预期工作,我可以导航到新文档,我可以看到漂亮的 INavigationAware 界面在我的视图模型上工作,完全符合我的要求。唯一的问题是,当第二次导航到(视图的 INavigationAware 确实按预期工作)时,实际的 Document(如选项卡控件中的选项卡)没有被激活(意味着选项卡变得可见)。

【问题讨论】:

  • INavigationAware 附带一个 OnNavigatedTo 事件。你试过用那个吗?我觉得这对这个有用。
  • 是的,但是这个事件在视图模型中触发,而不是在区域中。我希望能够在不更改所有文档视图模型类型的情况下挂接事件。
  • 并补充一点,我认为适配器应该解决这个问题,因为“选项卡”控件负责更新其视图,而不是它在选项卡中托管的视图模型的责任。
  • 现在就在你身边。祝你好运。
  • 谢谢理查德,感谢您的帮助。

标签: wpf devexpress prism prism-6


【解决方案1】:

我根据布赖恩的回答得到了它。对于任何对此感兴趣的人,我的解决方案是我首先使用视图在我的视图模型上实现 IPanelInfo。结果是,当再次导航到已经打开的文档面板时,它会被激活,而之前没有。注意目前测试不佳;-)

public class DocumentGroupAdapter : RegionAdapterBase<DocumentGroup>
{
    public DocumentGroupAdapter(IRegionBehaviorFactory behaviorFactory) :
        base(behaviorFactory)
    {
    }

    protected override IRegion CreateRegion()
    {
        return new SingleActiveRegion();
    }
    protected override void Adapt(IRegion region, DocumentGroup regionTarget)
    {
        region.Views.CollectionChanged += (s, e) => {
            OnViewsCollectionChanged(regionTarget, e);
        };
        var manager = regionTarget.GetDockLayoutManager();
        manager.DockItemClosing += (s, e) =>
        {
            Closing(region, e);
        };
        manager.ClosingBehavior = ClosingBehavior.ImmediatelyRemove;
    }

    protected override void AttachBehaviors(IRegion region, DocumentGroup regionTarget)
    {
        base.AttachBehaviors(region, regionTarget);

        if (!region.Behaviors.ContainsKey(DocumentGroupSyncBehavior.BehaviorKey))
            region.Behaviors.Add(DocumentGroupSyncBehavior.BehaviorKey, new DocumentGroupSyncBehavior() { HostControl = regionTarget });
    }


    private static void Closing(IRegion region, ItemEventArgs e)
    {
        var documentPanel = e.Item as DocumentPanel;
        var view = documentPanel?.Content;
        if (view == null) return;
        var v = view as FrameworkElement;
        var info = v?.DataContext as IPanelInfo;
        info?.Close();
        region.Remove(view);
    }

    private static void OnViewsCollectionChanged(DocumentGroup regionTarget, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
            foreach (var view in e.NewItems)
            {
                var manager = regionTarget.GetDockLayoutManager();
                var panel = manager.DockController.AddDocumentPanel(regionTarget);
                panel.Content = view;
                panel.ClosingBehavior = ClosingBehavior.ImmediatelyRemove;
                var v = view as FrameworkElement;
                var info = v?.DataContext as IPanelInfo;
                if (info != null)
                {
                    var myBinding = new Binding
                    {
                        Source = v.DataContext,
                        Path = new PropertyPath("Caption"),
                        Mode = BindingMode.TwoWay,
                        UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                    };
                    BindingOperations.SetBinding(panel, BaseLayoutItem.CaptionProperty, myBinding); 
                }
                manager.DockController.Activate(panel);
            }
    }
}

public class DocumentGroupSyncBehavior : RegionBehavior, IHostAwareRegionBehavior
{
    public const string BehaviorKey = "DocumentGroupRegionActiveAwareBehavior";

    private DocumentGroup _hostControl;
    public DependencyObject HostControl
    {
        get { return _hostControl; }
        set { _hostControl = value as DocumentGroup; }
    }

    protected override void OnAttach()
    {
        _hostControl.SelectedItemChanged += HostControl_SelectedItemChanged;
        Region.ActiveViews.CollectionChanged += ActiveViews_CollectionChanged;
    }

    private void HostControl_SelectedItemChanged(object sender, SelectedItemChangedEventArgs e)
    {
        if (e.OldItem != null)
        {
            var item = e.OldItem;
            //are we dealing with a DocumentPanel directly
            if (Region.Views.Contains(item) && Region.ActiveViews.Contains(item))
            {
                Region.Deactivate(item);
            }
            else
            {
                //now check to see if we have any views that were injected
                var contentControl = item as DocumentPanel;
                if (contentControl != null)
                {
                    var injectedView = contentControl.Content;
                    if (Region.Views.Contains(injectedView) && Region.ActiveViews.Contains(injectedView))
                        Region.Deactivate(injectedView);
                }
            }
        }

        if (e.Item != null)
        {
            var item = e.Item;

            //are we dealing with a DocumentPanel directly
            if (Region.Views.Contains(item) && !Region.ActiveViews.Contains(item))
            {
                Region.Activate(item);
            }
            else
            {
                //now check to see if we have any views that were injected
                var contentControl = item as DocumentPanel;
                if (contentControl != null)
                {
                    var injectedView = contentControl.Content;
                    if (Region.Views.Contains(injectedView) && !Region.ActiveViews.Contains(injectedView))
                        Region.Activate(injectedView);
                }
            }
        }
    }

    private void ActiveViews_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            //are we dealing with a view
            var frameworkElement = e.NewItems[0] as FrameworkElement;
            if (frameworkElement != null)
            {
                var documentPanel = GetContentPaneFromView(frameworkElement);
                if (documentPanel != null && !documentPanel.IsActive)
                    documentPanel.ActivateCommand.Execute(null);
            }
            else
            {
                //must be a viewmodel
                var viewModel = e.NewItems[0];
                var contentPane = GetContentPaneFromFromViewModel(viewModel);
                contentPane?.ActivateCommand.Execute(null);
            }
        }
    }

    private DocumentPanel GetContentPaneFromView(object view)
    {
        foreach (var baseLayoutItem in _hostControl.Items)
        {
            var contentPane = (DocumentPanel) baseLayoutItem;
            if (contentPane?.Content != null && contentPane.Content == view)
                return contentPane;
        }
        return null;
    }

    private DocumentPanel GetContentPaneFromFromViewModel(object viewModel)
    {
        foreach (var baseLayoutItem in _hostControl.Items)
        {
            var contentPane = (DocumentPanel) baseLayoutItem;
            var content = contentPane?.Content as FrameworkElement;
            if (content != null && content.DataContext == viewModel)
                return contentPane;
        }
        return null;
    }
}


public interface IPanelInfo
{
    string Caption { get; set; }
    void Close();
}

【讨论】:

    【解决方案2】:

    我不熟悉 DevExrpess 控件,但我有一个自定义区域适配器和 Infragistics xamDockManager 控件的 IActiveAware 行为。查看代码,看看您是否可以修改它以与您的控件供应商合作。

    https://github.com/brianlagunas/xamDockManager-Region-Adapter

    【讨论】:

    • 感谢 Brian,现在查看代码。我认为“诀窍”在 Region.Deactivate 方法中。这实际上是从区域中卸载视图,还是仅将视图标记为非活动视图,而是将其保留在内存和区域中?
    • 进一步研究似乎问题之一是文档组适配器被实现为 AllActiveRegion 。明天将进一步检查。感谢您指出我希望正确的方向;-)
    • 完美!很高兴我能帮上忙。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多