Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix overriding (Metro)TabItem controltemplate/style #3152

Merged
merged 2 commits into from
Jan 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,35 +117,47 @@ protected override void Invoke(object parameter)
}
}

var closeAction =
new Action(
() =>
{
// TODO Raise a closing event to cancel this action

if (tabControl.ItemsSource == null)
{
// if the list is hard-coded (i.e. has no ItemsSource)
// then we remove the item from the collection
tabControl.Items.Remove(tabItem);
}
else
if (tabControl is MetroTabControl && tabItem is MetroTabItem)
{
// run the command handler for the TabControl
// see #555
tabControl.BeginInvoke(() => ((MetroTabControl)tabControl).CloseThisTabItem((MetroTabItem)tabItem));
}
else
{
var closeAction =
new Action(
() =>
{
// if ItemsSource is something we cannot work with, bail out
var collection = tabControl.ItemsSource as IList;
if (collection == null)
// TODO Raise a closing event to cancel this action

if (tabControl.ItemsSource == null)
{
return;
// if the list is hard-coded (i.e. has no ItemsSource)
// then we remove the item from the collection
tabItem.ClearStyle();
tabControl.Items.Remove(tabItem);
}
// find the item and kill it (I mean, remove it)
var item2Remove = collection.OfType<object>().FirstOrDefault(item => tabItem == item || tabItem.DataContext == item);
if (item2Remove != null)
else
{
collection.Remove(item2Remove);
// if ItemsSource is something we cannot work with, bail out
var collection = tabControl.ItemsSource as IList;
if (collection == null)
{
return;
}

// find the item and kill it (I mean, remove it)
var item2Remove = collection.OfType<object>().FirstOrDefault(item => tabItem == item || tabItem.DataContext == item);
if (item2Remove != null)
{
tabItem.ClearStyle();
collection.Remove(item2Remove);
}
}
}
});
this.BeginInvoke(closeAction);
});
this.BeginInvoke(closeAction);
}
}

private static void OnCommandChanged(CloseTabItemAction action, DependencyPropertyChangedEventArgs e)
Expand Down Expand Up @@ -180,6 +192,7 @@ private void EnableDisableElement()
{
return;
}

var command = this.Command;
this.AssociatedObject.IsEnabled = command == null || command.CanExecute(this.GetCommandParameter());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,27 @@ public enum UnderlinedType

public static class TabControlHelper
{
/// Sets the Style and Template property to null.
///
/// Removing a TabItem in code behind can produce such nasty output
/// System.Windows.Data Warning: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TabControl', AncestorLevel='1''. BindingExpression:Path=Background; DataItem=null; target element is 'TabItem' (Name=''); target property is 'Background' (type 'Brush')
/// or
/// System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TabControl', AncestorLevel='1''. BindingExpression:Path=(0); DataItem=null; target element is 'TabItem' (Name=''); target property is 'UnderlineBrush' (type 'Brush')
///
/// This is a timing problem in WPF of the binding mechanism itself.
///
/// To avoid this, we can set the Style and Template to null.
public static void ClearStyle(this TabItem tabItem)
{
if (null == tabItem)
{
return;
}

tabItem.Template = null;
tabItem.Style = null;
}

/// <summary>
/// Identifies the CloseButtonEnabled attached property.
/// </summary>
Expand Down Expand Up @@ -156,6 +177,8 @@ public static UnderlinedType GetUnderlined(UIElement element)
return (UnderlinedType)element.GetValue(UnderlinedProperty);
}

[Category(AppName.MahApps)]
[AttachedPropertyBrowsableForType(typeof(TabControl))]
public static void SetUnderlined(UIElement element, UnderlinedType value)
{
element.SetValue(UnderlinedProperty, value);
Expand All @@ -168,15 +191,19 @@ public static void SetUnderlined(UIElement element, UnderlinedType value)
DependencyProperty.RegisterAttached("UnderlineBrush",
typeof(Brush),
typeof(TabControlHelper),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender));
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

[Category(AppName.MahApps)]
[AttachedPropertyBrowsableForType(typeof(TabControl))]
[AttachedPropertyBrowsableForType(typeof(TabItem))]
public static Brush GetUnderlineBrush(UIElement element)
{
return (Brush)element.GetValue(UnderlineBrushProperty);
}

[Category(AppName.MahApps)]
[AttachedPropertyBrowsableForType(typeof(TabControl))]
[AttachedPropertyBrowsableForType(typeof(TabItem))]
public static void SetUnderlineBrush(UIElement element, Brush value)
{
element.SetValue(UnderlineBrushProperty, value);
Expand All @@ -189,15 +216,19 @@ public static void SetUnderlineBrush(UIElement element, Brush value)
DependencyProperty.RegisterAttached("UnderlineSelectedBrush",
typeof(Brush),
typeof(TabControlHelper),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender));
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

[Category(AppName.MahApps)]
[AttachedPropertyBrowsableForType(typeof(TabControl))]
[AttachedPropertyBrowsableForType(typeof(TabItem))]
public static Brush GetUnderlineSelectedBrush(UIElement element)
{
return (Brush)element.GetValue(UnderlineSelectedBrushProperty);
}

[Category(AppName.MahApps)]
[AttachedPropertyBrowsableForType(typeof(TabControl))]
[AttachedPropertyBrowsableForType(typeof(TabItem))]
public static void SetUnderlineSelectedBrush(UIElement element, Brush value)
{
element.SetValue(UnderlineSelectedBrushProperty, value);
Expand All @@ -210,15 +241,19 @@ public static void SetUnderlineSelectedBrush(UIElement element, Brush value)
DependencyProperty.RegisterAttached("UnderlineMouseOverBrush",
typeof(Brush),
typeof(TabControlHelper),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender));
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

[Category(AppName.MahApps)]
[AttachedPropertyBrowsableForType(typeof(TabControl))]
[AttachedPropertyBrowsableForType(typeof(TabItem))]
public static Brush GetUnderlineMouseOverBrush(UIElement element)
{
return (Brush)element.GetValue(UnderlineMouseOverBrushProperty);
}

[Category(AppName.MahApps)]
[AttachedPropertyBrowsableForType(typeof(TabControl))]
[AttachedPropertyBrowsableForType(typeof(TabItem))]
public static void SetUnderlineMouseOverBrush(UIElement element, Brush value)
{
element.SetValue(UnderlineMouseOverBrushProperty, value);
Expand All @@ -231,15 +266,19 @@ public static void SetUnderlineMouseOverBrush(UIElement element, Brush value)
DependencyProperty.RegisterAttached("UnderlineMouseOverSelectedBrush",
typeof(Brush),
typeof(TabControlHelper),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender));
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

[Category(AppName.MahApps)]
[AttachedPropertyBrowsableForType(typeof(TabControl))]
[AttachedPropertyBrowsableForType(typeof(TabItem))]
public static Brush GetUnderlineMouseOverSelectedBrush(UIElement element)
{
return (Brush)element.GetValue(UnderlineMouseOverSelectedBrushProperty);
}

[Category(AppName.MahApps)]
[AttachedPropertyBrowsableForType(typeof(TabControl))]
[AttachedPropertyBrowsableForType(typeof(TabItem))]
public static void SetUnderlineMouseOverSelectedBrush(UIElement element, Brush value)
{
element.SetValue(UnderlineMouseOverSelectedBrushProperty, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ internal void CloseThisTabItem([NotNull] MetroTabItem tabItem)
{
// if the list is hard-coded (i.e. has no ItemsSource)
// then we remove the item from the collection
tabItem.ClearStyle();
this.Items.Remove(tabItem);
}
else
Expand All @@ -160,6 +161,7 @@ internal void CloseThisTabItem([NotNull] MetroTabItem tabItem)
var item2Remove = collection.OfType<object>().FirstOrDefault(item => tabItem == item || tabItem.DataContext == item);
if (item2Remove != null)
{
tabItem.ClearStyle();
collection.Remove(item2Remove);
}
}
Expand Down
40 changes: 0 additions & 40 deletions src/MahApps.Metro/MahApps.Metro.Shared/Controls/MetroTabItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,6 @@ public class MetroTabItem : TabItem
public MetroTabItem()
{
DefaultStyleKey = typeof(MetroTabItem);
this.InternalCloseTabCommand = new CloseCommand(InternalCloseTabCommandCanExecute, InternalCloseTabCommandExecuteAction);
}

private void InternalCloseTabCommandExecuteAction(object o)
{
var closeTabCommand = this.CloseTabCommand;
if (closeTabCommand != null)
{
var closeTabCommandParameter = this.CloseTabCommandParameter ?? this;
if (closeTabCommand.CanExecute(closeTabCommandParameter))
{
// force the command handler to run
closeTabCommand.Execute(closeTabCommandParameter);
}
}

var owningTabControl = this.TryFindParent<BaseMetroTabControl>();
// run the command handler for the TabControl
// see #555
owningTabControl?.BeginInvoke(() => owningTabControl.CloseThisTabItem(this));
}

private bool InternalCloseTabCommandCanExecute(object o)
{
var closeTabCommand = this.CloseTabCommand;
return closeTabCommand == null || closeTabCommand.CanExecute(this.CloseTabCommandParameter ?? this);
}

public static readonly DependencyProperty CloseButtonEnabledProperty =
Expand All @@ -55,20 +29,6 @@ public bool CloseButtonEnabled
set { SetValue(CloseButtonEnabledProperty, value); }
}

internal static readonly DependencyProperty InternalCloseTabCommandProperty =
DependencyProperty.Register("InternalCloseTabCommand",
typeof(ICommand),
typeof(MetroTabItem));

/// <summary>
/// Gets/sets the command that is executed when the Close Button is clicked.
/// </summary>
internal ICommand InternalCloseTabCommand
{
get { return (ICommand)GetValue(InternalCloseTabCommandProperty); }
set { SetValue(InternalCloseTabCommandProperty, value); }
}

public static readonly DependencyProperty CloseTabCommandProperty =
DependencyProperty.Register("CloseTabCommand",
typeof(ICommand),
Expand Down
12 changes: 8 additions & 4 deletions src/MahApps.Metro/MahApps.Metro/Styles/Controls.TabControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@
<Setter Property="BorderThickness" Value="0" />
<!-- special property for header font size -->
<Setter Property="Controls:ControlsHelper.HeaderFontSize" Value="{DynamicResource TabItemFontSize}" />
<Setter Property="Controls:TabControlHelper.UnderlineBrush" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=(Controls:TabControlHelper.UnderlineBrush), Mode=OneWay}" />
<Setter Property="Controls:TabControlHelper.UnderlineMouseOverBrush" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=(Controls:TabControlHelper.UnderlineMouseOverBrush), Mode=OneWay}" />
<Setter Property="Controls:TabControlHelper.UnderlineMouseOverSelectedBrush" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=(Controls:TabControlHelper.UnderlineMouseOverSelectedBrush), Mode=OneWay}" />
<Setter Property="Controls:TabControlHelper.UnderlineSelectedBrush" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=(Controls:TabControlHelper.UnderlineSelectedBrush), Mode=OneWay}" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Foreground" Value="{DynamicResource TextBrush}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
Expand Down Expand Up @@ -155,7 +159,7 @@
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="{TemplateBinding Background}"
BorderBrush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=(Controls:TabControlHelper.UnderlineBrush), Mode=OneWay}"
BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:TabControlHelper.UnderlineBrush), Mode=OneWay}"
LineExtent="3"
LineThickness="2"
Placement="Bottom"
Expand Down Expand Up @@ -221,7 +225,7 @@

<Trigger Property="IsSelected" Value="true">
<Setter TargetName="ContentSite" Property="TextElement.Foreground" Value="{DynamicResource AccentColorBrush}" />
<Setter TargetName="Underline" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=(Controls:TabControlHelper.UnderlineSelectedBrush), Mode=OneWay}" />
<Setter TargetName="Underline" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:TabControlHelper.UnderlineSelectedBrush), Mode=OneWay}" />
</Trigger>
<Trigger Property="IsSelected" Value="false">
<Setter TargetName="ContentSite" Property="TextElement.Foreground" Value="{DynamicResource GrayNormalBrush}" />
Expand All @@ -244,7 +248,7 @@

<Trigger SourceName="Border" Property="IsMouseOver" Value="True">
<Setter TargetName="ContentSite" Property="TextElement.Foreground" Value="{DynamicResource GrayHoverBrush}" />
<Setter TargetName="Underline" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=(Controls:TabControlHelper.UnderlineMouseOverBrush), Mode=OneWay}" />
<Setter TargetName="Underline" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:TabControlHelper.UnderlineMouseOverBrush), Mode=OneWay}" />
</Trigger>

<MultiDataTrigger>
Expand All @@ -270,7 +274,7 @@
<Condition Property="IsSelected" Value="True" />
</MultiTrigger.Conditions>
<Setter TargetName="ContentSite" Property="TextElement.Foreground" Value="{DynamicResource HighlightBrush}" />
<Setter TargetName="Underline" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=(Controls:TabControlHelper.UnderlineMouseOverSelectedBrush), Mode=OneWay}" />
<Setter TargetName="Underline" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:TabControlHelper.UnderlineMouseOverSelectedBrush), Mode=OneWay}" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Expand Down
Loading