Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Replaced TabControl with TabControlEx #143

Merged
merged 1 commit into from
Apr 12, 2020
Merged

Conversation

matko238
Copy link

LayoutDocumentPaneControl and LayoutAnchorablePaneControl were derived from regular WPF TabControl. I replaced it with TabControlEx which supports virtualization of tab controls to increase performance. See issue #142 for more details.

TODO: Someone may not like this behavior. An option should be added at DockingManager level or as a property of LayoutAnchorable so it retains original behavior (documents are unloaded/loaded when "tabs"/documents are changed.

LayoutDocumentPaneControl and LayoutAnchorablePaneControl were derived from regular WPF TabControl. I replaced it with TabControlEx which supports virtualization of tab controls to increase performance.
@Dirkster99
Copy link
Owner

Making LayoutDocumentPaneControl and LayoutAnchorablePaneControl virtualized TabControls would be a cool contribution indeed :-)

To make this configurable I suggest that we add:

  1. related simple (non-dependency) property for each case inside the DockingManager:
  #region IsVirtualizingLayoutDocument IsVirtualizingLayoutAnchorable

/// <summary>
  /// Gets/sets (a simple non-dependency property) to determine whether the
  /// <see cref="LayoutDocumentPaneControl"/> is virtualizing its child controls or not.
  /// </summary>
  public bool IsVirtualizingLayoutDocument { get; set; }
  
  /// <summary>
  /// Gets/sets (a simple non-dependency property) to determine whether the
  /// <see cref="LayoutAnchorablePaneControl"/> is virtualizing its child controls or not.
  /// </summary>
  public bool IsVirtualizingLayoutAnchorable { get; set; }

#endregion IsVirtualizingLayoutDocument IsVirtualizingLayoutAnchorable

at about line 1322 in the DockingManager.cs file. The default should be false (not virtualizing) so this is should be OK as is.

  1. Next, we need to add a field and adjust/add constructors in LayoutDocumentPaneControl and LayoutAnchorablePaneControl. Actually, this field/property should be added in TabControlEx and we need to call a custom TabControlEx constructor instead of the default constructor
  #region fields
  private LayoutDocumentPane _model;
  private bool _IsVirtualizing;
  #endregion fields

  #region Constructors
  /// <summary>Static class constructor to register WPF style keys.</summary>
  static LayoutDocumentPaneControl()
  {
      FocusableProperty.OverrideMetadata(typeof(LayoutDocumentPaneControl), new FrameworkPropertyMetadata(false));
  }

  /// <summary>Class constructor from model parameter.</summary>
  /// <param name="model"></param>
  /// <param name="IsVirtualizing"></param>
  internal LayoutDocumentPaneControl(LayoutDocumentPane model, bool IsVirtualizing)
  {
      _IsVirtualizing = IsVirtualizing;
  }

  /// <summary>Class constructor from model parameter.</summary>
  /// <param name="model"></param>
  internal LayoutDocumentPaneControl(LayoutDocumentPane model)
  {
      _model = model ?? throw new ArgumentNullException(nameof(model));
      SetBinding(ItemsSourceProperty, new Binding("Model.Children") { Source = this });
      SetBinding(FlowDirectionProperty, new Binding("Model.Root.Manager.FlowDirection") { Source = this });
      // Handle SizeChanged event instead of LayoutUpdated. It will exclude fluctuations of Actual size values.
      // this.LayoutUpdated += new EventHandler( OnLayoutUpdated );
      this.SizeChanged += OnSizeChanged;
  }
  #endregion Constructors
  #region fields
  private LayoutAnchorablePane _model;
  private bool _IsVirtualizing;
  #endregion fields

  #region Constructors

  static LayoutAnchorablePaneControl()
  {
      FocusableProperty.OverrideMetadata(typeof(LayoutAnchorablePaneControl), new FrameworkPropertyMetadata(false));
  }

  /// <summary>Class constructor from model parameter.</summary>
  /// <param name="model"></param>
  /// <param name="IsVirtualizing"></param>
  public LayoutAnchorablePaneControl(LayoutAnchorablePane model, bool IsVirtualizing)
      : this(model)
  {
      _IsVirtualizing = IsVirtualizing;
  }

  /// <summary>Class constructor from model parameter.</summary>
  /// <param name="model"></param>
  public LayoutAnchorablePaneControl(LayoutAnchorablePane model)
  {
      _model = model ?? throw new ArgumentNullException(nameof(model));
      SetBinding(ItemsSourceProperty, new Binding("Model.Children") { Source = this });
      SetBinding(FlowDirectionProperty, new Binding("Model.Root.Manager.FlowDirection") { Source = this });
      // Handle SizeChanged event instead of LayoutUpdated. It will exclude fluctuations of Actual size values.
      // this.LayoutUpdated += new EventHandler( OnLayoutUpdated );
      SizeChanged += OnSizeChanged;
  }

  #endregion Constructors
  1. We also need to adjust the code inside TabControlEx to switch virtualization ON and OFF at construction time.

  2. Last, but not least we need to adjust constructor statements in the DockingManager to configure non-virtualized/virtualized controls of the above controls.

For the LayoutDocumentPaneControl adjust the constructor statement in DockingManager:

  • at line 1523 change:
    var templateModelView = new LayoutDocumentPaneControl(model as LayoutDocumentPane);
    into
    var templateModelView = new LayoutDocumentPaneControl(model as LayoutDocumentPane, IsVirtualizingLayoutDocument);

For the LayoutAnchorablePaneControl adjust the constructor statement in DockingManager:

  • at line 1529 change:
    var templateModelView = new LayoutAnchorablePaneControl(model as LayoutAnchorablePane);
    into
    var templateModelView = new LayoutAnchorablePaneControl(model as LayoutAnchorablePane, IsVirtualizingLayoutAnchorable);

This implementation would allow a client application to set this configuration at start-up time and I'd like to make it a non-binding property so people do not expect to be able to change this at run-time:

 <avalonDock:DockingManager
     x:Name="dockManager"
     IsVirtualizingLayoutAnchorable="True"
     IsVirtualizingLayoutDocument="True"
...
 </avalonDock:DockingManager

Summary

What I am not sure about is how to add this configuration setting into the TabControlEx such that it can be used in a virtualizing and non-virtualizing mode. But I understand its possible?

Would you please re-order the methods in TabControlEx by their accessibility (public, override, protected, private) and use regions (fields, constructors, properties, methods) and add comments for all non-private items as we now established in the rest of the code?

I think you would just have to make these changes in your fork, test them, and if you are happy with your test, commit it into your fork. The PR should then update to list the additional commit(s) and tracking this change in Dirkster/AvalonDock master would be much easier because the feature addition/change is visible in one place :-)

What do you think about this solution? Would this work for you and for others since the defaults remain the same?

@matko238
Copy link
Author

I think this would work (other docking solutions do this, the original xceed dock does it (see the issue and release note). As for your question, I'm not sure either but I guess I can modify TabControlEx so it doesn't apply template if parent control (LayoutAnchorable or LayoutDocument) doesn't have corresponding "Virtualizing" property set to true.

@Dirkster99
Copy link
Owner

Hi @matko238 I was just wondering if you are going to complete the above changes.

If not could you please let me know:

  • how I can adjust between virtualization and non-virtualization in the TabControlEx class and
  • how I can use a demo control to test the different behavior and I'll try to figure out the rest…

Thanx Drk

@matko238
Copy link
Author

Hi,
I'm just too busy now at work but as soon as things slow down a bit I will get back to this but I have no idea when :/

But if you want you can finish it - to disable virtualization I guess it will be enough to skip OnApplyTemplate inside TabControlEx. To test if it is disabled, create simplest dock with two documents with user controls inside them and subscribe to Unloaded event inside user control - if it fires, virtualization is off.

@Dirkster99 Dirkster99 merged commit 74641ff into Dirkster99:master Apr 12, 2020
@Dirkster99
Copy link
Owner

OK, I merged and added it as described - I am glad we made this optional because I already see an issue #148 with LayoutAnchoreables when virtualization is turned ON. I have not looked into it but it seems like the number of items is not reported correctly (it seems to think the count is 1) when virtualization is turned on(?)

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants