-
Notifications
You must be signed in to change notification settings - Fork 324
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #143 from matko238/master
Replaced TabControl with TabControlEx
- Loading branch information
Showing
3 changed files
with
205 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
using System; | ||
using System.Collections.Specialized; | ||
using System.Windows; | ||
using System.Windows.Controls; | ||
using System.Windows.Controls.Primitives; | ||
using System.Windows.Data; | ||
|
||
namespace AvalonDock | ||
{ | ||
/// <summary> | ||
/// This control added to mitigate issue with tab (document) switching speed | ||
/// See this https://stackoverflow.com/questions/2080764/how-to-preserve-control-state-within-tab-items-in-a-tabcontrol | ||
/// and this https://stackoverflow.com/questions/31030293/cefsharp-in-tabcontrol-not-working/37171847#37171847 | ||
/// </summary> | ||
[TemplatePart(Name = "PART_ItemsHolder", Type = typeof(Panel))] | ||
public class TabControlEx : TabControl | ||
{ | ||
private Panel ItemsHolderPanel = null; | ||
|
||
public TabControlEx() | ||
: base() | ||
{ | ||
// This is necessary so that we get the initial databound selected item | ||
ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged; | ||
} | ||
|
||
/// <summary> | ||
/// If containers are done, generate the selected item | ||
/// </summary> | ||
/// <param name="sender"></param> | ||
/// <param name="e"></param> | ||
private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e) | ||
{ | ||
if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) | ||
{ | ||
this.ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged; | ||
UpdateSelectedItem(); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Get the ItemsHolder and generate any children | ||
/// </summary> | ||
public override void OnApplyTemplate() | ||
{ | ||
base.OnApplyTemplate(); | ||
ItemsHolderPanel = CreateGrid(); | ||
// exchange ContentPresenter for Grid | ||
var topGrid = (Grid)GetVisualChild(0); | ||
|
||
if (topGrid != null) | ||
{ | ||
if (topGrid.Children != null && topGrid.Children.Count > 2) | ||
{ | ||
if (topGrid.Children[1] is Border) | ||
{ | ||
var border = (Border)topGrid.Children[1]; | ||
border.Child = ItemsHolderPanel; | ||
} | ||
else if (topGrid.Children[2] is Border) | ||
{ | ||
var border = (Border)topGrid.Children[2]; | ||
border.Child = ItemsHolderPanel; | ||
} | ||
} | ||
} | ||
|
||
UpdateSelectedItem(); | ||
} | ||
|
||
private Grid CreateGrid() | ||
{ | ||
var grid = new Grid(); | ||
Binding binding = new Binding(PaddingProperty.Name); | ||
binding.Source = this; // view model? | ||
grid.SetBinding(Grid.MarginProperty, binding); | ||
|
||
binding = new Binding(SnapsToDevicePixelsProperty.Name); | ||
binding.Source = this; // view model? | ||
grid.SetBinding(Grid.SnapsToDevicePixelsProperty, binding); | ||
|
||
return grid; | ||
} | ||
|
||
/// <summary> | ||
/// When the items change we remove any generated panel children and add any new ones as necessary | ||
/// </summary> | ||
/// <param name="e"></param> | ||
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) | ||
{ | ||
base.OnItemsChanged(e); | ||
|
||
if (ItemsHolderPanel == null) | ||
return; | ||
|
||
switch (e.Action) | ||
{ | ||
case NotifyCollectionChangedAction.Reset: | ||
ItemsHolderPanel.Children.Clear(); | ||
break; | ||
|
||
case NotifyCollectionChangedAction.Add: | ||
case NotifyCollectionChangedAction.Remove: | ||
if (e.OldItems != null) | ||
{ | ||
foreach (var item in e.OldItems) | ||
{ | ||
ContentPresenter cp = FindChildContentPresenter(item); | ||
if (cp != null) | ||
ItemsHolderPanel.Children.Remove(cp); | ||
} | ||
} | ||
|
||
// Don't do anything with new items because we don't want to | ||
// create visuals that aren't being shown | ||
|
||
UpdateSelectedItem(); | ||
break; | ||
|
||
case NotifyCollectionChangedAction.Replace: | ||
throw new NotImplementedException("Replace not implemented yet"); | ||
} | ||
} | ||
|
||
protected override void OnSelectionChanged(SelectionChangedEventArgs e) | ||
{ | ||
base.OnSelectionChanged(e); | ||
UpdateSelectedItem(); | ||
} | ||
|
||
private void UpdateSelectedItem() | ||
{ | ||
if (ItemsHolderPanel == null) | ||
return; | ||
|
||
// Generate a ContentPresenter if necessary | ||
TabItem item = GetSelectedTabItem(); | ||
if (item != null) | ||
CreateChildContentPresenter(item); | ||
|
||
// show the right child | ||
foreach (ContentPresenter child in ItemsHolderPanel.Children) | ||
child.Visibility = ((child.Tag as TabItem).IsSelected) ? Visibility.Visible : Visibility.Collapsed; | ||
} | ||
|
||
private ContentPresenter CreateChildContentPresenter(object item) | ||
{ | ||
if (item == null) | ||
return null; | ||
|
||
ContentPresenter cp = FindChildContentPresenter(item); | ||
|
||
if (cp != null) | ||
return cp; | ||
|
||
// the actual child to be added. cp.Tag is a reference to the TabItem | ||
cp = new ContentPresenter(); | ||
cp.Content = (item is TabItem) ? (item as TabItem).Content : item; | ||
cp.ContentTemplate = this.SelectedContentTemplate; | ||
cp.ContentTemplateSelector = this.SelectedContentTemplateSelector; | ||
cp.ContentStringFormat = this.SelectedContentStringFormat; | ||
cp.Visibility = Visibility.Collapsed; | ||
cp.Tag = (item is TabItem) ? item : (this.ItemContainerGenerator.ContainerFromItem(item)); | ||
ItemsHolderPanel.Children.Add(cp); | ||
return cp; | ||
} | ||
|
||
private ContentPresenter FindChildContentPresenter(object data) | ||
{ | ||
if (data is TabItem) | ||
data = (data as TabItem).Content; | ||
|
||
if (data == null) | ||
return null; | ||
|
||
if (ItemsHolderPanel == null) | ||
return null; | ||
|
||
foreach (ContentPresenter cp in ItemsHolderPanel.Children) | ||
{ | ||
if (cp.Content == data) | ||
return cp; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
protected TabItem GetSelectedTabItem() | ||
{ | ||
object selectedItem = base.SelectedItem; | ||
if (selectedItem == null) | ||
return null; | ||
|
||
TabItem item = selectedItem as TabItem; | ||
if (item == null) | ||
item = base.ItemContainerGenerator.ContainerFromIndex(base.SelectedIndex) as TabItem; | ||
|
||
return item; | ||
} | ||
} | ||
} |