I am using DevExpress's DocumentGroup and DocumentGroupAdapter (described in E3339 on their site) for a WPF application with PRISM 6. I am using scoped regions and INavigationAware and everything works as expected, I can navigate to new documents and I can see the beautiful INavigationAware interface working on my view models, exactly as I want. The only problem is that the actual Document ( like a tab in a tab control) does not get activated (meaning the tab becomes visible) when navigated to for a second time ( the INavigationAware for the views does work as expected).
Asked
Active
Viewed 715 times
1
-
There is an OnNavigatedTo event that comes with INavigationAware. Have you tried using that? I feel like that will work for this. – R. Richards Nov 29 '16 at 22:10
-
Yes but this event fires in the viewmodel not in the region. I would like to be able to hook in the event without having to change all my document view model types. – Aktaeon Nov 29 '16 at 22:31
-
and to add, I think the adapter should solve this problem as it is the responsibility of the "tab" control to update its view, not that of the view model that it is hosting in the tab. – Aktaeon Nov 29 '16 at 22:42
-
Right there with you now. Good luck. – R. Richards Nov 29 '16 at 22:44
-
Thanks Richard, I appreciate the help. – Aktaeon Nov 29 '16 at 22:47
2 Answers
1
I got it working based on the answer of Brian. For anyone interested here is my solution where I implement the IPanelInfo on my viewmodel using view first. The result is that when navigating again to an already open documentpanel it gets activated, whereas before it did not. Note poorly tested at the moment ;-)
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();
}

Aktaeon
- 189
- 2
- 14
0
I am not familiar with DevExrpess control, but I have a custom region adapter and IActiveAware behavior for the Infragistics xamDockManager control. Check out the code and see if you can modify it to work with your control vendor.
https://github.com/brianlagunas/xamDockManager-Region-Adapter
-
Thanks Brian, going through the code now. I think the 'trick' is in the Region.Deactivate method. Does this actually unload the view from the region, or does it merely mark the view as not the active one but keeping it in memory and in the region? – Aktaeon Nov 29 '16 at 22:39
-
Looking further into it it seems that one of the problems is that the document group adapter is implemented as an AllActiveRegion . Will check tomorrow further. Thanks for pointing me out in hopefully the right direction ;-) – Aktaeon Nov 29 '16 at 23:14
-