简体   繁体   中英

TabControl inherited CustomControl doesn't show anything

First of all I'm an amateur and non-english native speaker, so I would appreciate it if you would have a little patience with me ;)

Following another stackoverflow question, I've done a TabControl that expands itself (like an expander) just modifying the template of the original TabControl, so I can just alter the height of the control when any tab is selected.
That worked perfect, but needed some ViewModel properties for the logic. Now i need to use that control again and i thought the better way would be to make a CustomControl.

The problem I'm having is that the CustomControl are just lookless, no style are applied to it although I have specified styles for it in the Generic.xaml file, and the Build Action property to Page , revised the AsemblyInfo.cs , and used the DefaultStyleKeyProperty.OverrideMetadata in the static constructor. All following other questions suggestions.

I think it'd be better to show the code I have now and then explain what more I've tried, I have to say that I was writing the logic when I noticed this, so it does not work right now.

Generic.xaml:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PRUEBA_TABBEDEXPANDER"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"  
xmlns:ie="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
xmlns:Core="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions" 
xmlns:int="clr-namespace:System.Windows.Interactivity">

<SolidColorBrush x:Key="TabControlNormalBorderBrush" Color="#8C8E94"/>
<Style x:Key="TabItemFocusVisual">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <Rectangle Margin="3,3,3,1" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
    <GradientStop Color="#F3F3F3" Offset="0"/>
    <GradientStop Color="#EBEBEB" Offset="0.5"/>
    <GradientStop Color="#DDDDDD" Offset="0.5"/>
    <GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="TabItemHotBackground" EndPoint="0,1" StartPoint="0,0">
    <GradientStop Color="#EAF6FD" Offset="0.15"/>
    <GradientStop Color="#D9F0FC" Offset=".5"/>
    <GradientStop Color="#BEE6FD" Offset=".5"/>
    <GradientStop Color="#A7D9F5" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="TabItemSelectedBackground" Color="#F9F9F9"/>
<SolidColorBrush x:Key="TabItemHotBorderBrush" Color="#3C7FB1"/>
<SolidColorBrush x:Key="TabItemDisabledBackground" Color="#F4F4F4"/>
<SolidColorBrush x:Key="TabItemDisabledBorderBrush" Color="#FFC9C7BA"/>
<Style x:Key="TabItemStyle1" TargetType="{x:Type TabItem}">
    <Setter Property="FocusVisualStyle" Value="{StaticResource TabItemFocusVisual}"/>
    <Setter Property="Foreground" Value="Black"/>
    <Setter Property="Padding" Value="6,1,6,1"/>
    <Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/>
    <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    <Setter Property="VerticalContentAlignment" Value="Stretch"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabItem}">
                <Grid SnapsToDevicePixels="true">
                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,0" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}">
                        <ToggleButton x:Name="Content" Content="{TemplateBinding Header}">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="Click">
                                    <ei:CallMethodAction MethodName="ToggleButton_Click"
                                                         TargetObject="{Binding RelativeSource={RelativeSource TemplatedParent}}"/>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </ToggleButton>
                        <!--<ContentPresenter x:Name="Content" ContentSource="Header" 
                            HorizontalAlignment="{Binding HorizontalContentAlignment, 
                            RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" 
                            RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                            VerticalAlignment="{Binding VerticalContentAlignment, 
                            RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>-->
                    </Border>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter Property="Background" TargetName="Bd" Value="{StaticResource TabItemHotBackground}"/>
                    </Trigger>
                    <Trigger Property="IsSelected" Value="true">
                        <Setter Property="Panel.ZIndex" Value="1"/>
                        <Setter Property="Background" TargetName="Bd" Value="{StaticResource TabItemSelectedBackground}"/>
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsSelected" Value="false"/>
                            <Condition Property="IsMouseOver" Value="true"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource TabItemHotBorderBrush}"/>
                    </MultiTrigger>
                    <Trigger Property="TabStripPlacement" Value="Bottom">
                        <Setter Property="BorderThickness" TargetName="Bd" Value="1,0,1,1"/>
                    </Trigger>
                    <Trigger Property="TabStripPlacement" Value="Left">
                        <Setter Property="BorderThickness" TargetName="Bd" Value="1,1,0,1"/>
                    </Trigger>
                    <Trigger Property="TabStripPlacement" Value="Right">
                        <Setter Property="BorderThickness" TargetName="Bd" Value="0,1,1,1"/>
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsSelected" Value="true"/>
                            <Condition Property="TabStripPlacement" Value="Top"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Margin" Value="-2,-2,-2,-1"/>
                        <Setter Property="Margin" TargetName="Content" Value="0,0,0,1"/>
                    </MultiTrigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsSelected" Value="true"/>
                            <Condition Property="TabStripPlacement" Value="Bottom"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Margin" Value="-2,-1,-2,-2"/>
                        <Setter Property="Margin" TargetName="Content" Value="0,1,0,0"/>
                    </MultiTrigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsSelected" Value="true"/>
                            <Condition Property="TabStripPlacement" Value="Left"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Margin" Value="-2,-2,-1,-2"/>
                        <Setter Property="Margin" TargetName="Content" Value="0,0,1,0"/>
                    </MultiTrigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsSelected" Value="true"/>
                            <Condition Property="TabStripPlacement" Value="Right"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Margin" Value="-1,-2,-2,-2"/>
                        <Setter Property="Margin" TargetName="Content" Value="1,0,0,0"/>
                    </MultiTrigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Background" TargetName="Bd" Value="{StaticResource TabItemDisabledBackground}"/>
                        <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource TabItemDisabledBorderBrush}"/>
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="TabbedExpanderTabControlStyle" TargetType="{x:Type TabControl}">
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="Padding" Value="4,4,4,4"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/>
    <Setter Property="Background" Value="#F9F9F9"/>
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="ItemContainerStyle" Value="{StaticResource TabItemStyle1}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabControl}">
                <Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition x:Name="ColumnDefinition0"/>
                        <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition x:Name="RowDefinition0" Height="Auto"/>
                        <RowDefinition x:Name="RowDefinition1" Height="*"/>
                    </Grid.RowDefinitions>
                    <TabPanel x:Name="HeaderPanel" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
                    <Border x:Name="ContentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
                        <ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </Border>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="TabStripPlacement" Value="Bottom">
                        <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="1"/>
                        <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
                        <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                        <Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
                        <Setter Property="Margin" TargetName="HeaderPanel" Value="2,0,2,2"/>
                    </Trigger>
                    <Trigger Property="TabStripPlacement" Value="Left">
                        <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
                        <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
                        <Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/>
                        <Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/>
                        <Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
                        <Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
                        <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                        <Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
                        <Setter Property="Margin" TargetName="HeaderPanel" Value="2,2,0,2"/>
                    </Trigger>
                    <Trigger Property="TabStripPlacement" Value="Right">
                        <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
                        <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
                        <Setter Property="Grid.Column" TargetName="HeaderPanel" Value="1"/>
                        <Setter Property="Grid.Column" TargetName="ContentPanel" Value="0"/>
                        <Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
                        <Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
                        <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                        <Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
                        <Setter Property="Margin" TargetName="HeaderPanel" Value="0,2,2,2"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="TabbedExpanderStyle" TargetType="{x:Type local:TabbedExpander}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:TabbedExpander}">
                <Grid>
                    <TabControl Style="{StaticResource TabbedExpanderTabControlStyle}"></TabControl>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

TabbedExpander.cs:

public class TabbedExpander : TabControl, INotifyPropertyChanged
{
    static TabbedExpander()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(TabbedExpander), new FrameworkPropertyMetadata(typeof(TabbedExpander)));
    }

    #region dependency properties


    public ObservableCollection<object> ItemsS
    {
        get { return (ObservableCollection<object>)GetValue(ItemsSProperty); }
        set { SetValue(ItemsSProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ItemsS.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ItemsSProperty =
        DependencyProperty.Register("ItemsS", typeof(ObservableCollection<object>), typeof(TabbedExpander), 
            new PropertyMetadata(new ObservableCollection<object>(), OnItemsSPropertyChanged));
    private static void OnItemsSPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        TabbedExpander control = d as TabbedExpander;

        var old = e.OldValue as ObservableCollection<object>;

        if (old != null)
        {
            // Unsubscribe from CollectionChanged on the old collection
            old.CollectionChanged -= control.ItemsSCollectionChanged;
        }

        var n = e.NewValue as ObservableCollection<object>;

        if (n != null)
        {
            // Subscribe to CollectionChanged on the new collection
            n.CollectionChanged += control.ItemsSCollectionChanged;
        }
    }
    private void ItemsSCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Reset) base.Items.Clear();

        if (e.NewItems != null)
        {
            foreach (object item in e.NewItems)
            {
                base.Items.Add(item);
            }
        }

        if (e.OldItems != null)
        {
            foreach (object item in e.OldItems)
            {
                base.Items.RemoveAt(e.OldStartingIndex);
            }
        }
    }


    #region public
    public bool IsExpanded
    {
        get { return (bool)GetValue(IsExpandedProperty); }
        set { SetValue(IsExpandedProperty, value); }
    }
    public double EXPANDER_OFFSET
    {
        get { return (double)GetValue(EXPANDER_OFFSETProperty); }
        set { SetValue(EXPANDER_OFFSETProperty, value); }
    }
    public int EXPANDER_MIN_HEIGHT
    {
        get { return (int)GetValue(EXPANDER_MIN_HEIGHTProperty); }
        set { SetValue(EXPANDER_MIN_HEIGHTProperty, value); }
    }
    public int EXPANDER_MAX_HEIGHT
    {
        get { return (int)GetValue(EXPANDER_MAX_HEIGHTProperty); }
        set { SetValue(EXPANDER_MAX_HEIGHTProperty, value); }
    }
    public int EXPANDER_NOTEXPANDED_HEIGHT
    {
        get { return (int)GetValue(EXPANDER_NOTEXPANDED_HEIGHTProperty); }
        set { SetValue(EXPANDER_NOTEXPANDED_HEIGHTProperty, value); }
    }
    public double EXPANDER_EXPANDED_HEIGHT
    {
        get { return (double)GetValue(EXPANDER_EXPANDED_HEIGHTProperty); }
        set { SetValue(EXPANDER_EXPANDED_HEIGHTProperty, value); }
    }
    #endregion

    #region static
    public static readonly DependencyProperty IsExpandedProperty =
        DependencyProperty.Register("IsExpanded",
            typeof(bool),
            typeof(TabbedExpander),
            new PropertyMetadata(false, OnIsExpandedChanged));
    private static void OnIsExpandedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        TabbedExpander control = d as TabbedExpander;

        if ((bool)e.NewValue) control.Height = control.EXPANDER_EXPANDED_HEIGHT;
        else control.Height = control.EXPANDER_NOTEXPANDED_HEIGHT;
    }

    public static readonly DependencyProperty EXPANDER_OFFSETProperty =
        DependencyProperty.Register("EXPANDER_OFFSET",
            typeof(double),
            typeof(TabbedExpander),
            new PropertyMetadata(102d, OnOffsetChanged));
    private static void OnOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        throw new NotImplementedException();
    }

    public static readonly DependencyProperty EXPANDER_MIN_HEIGHTProperty =
        DependencyProperty.Register("EXPANDER_MIN_HEIGHT",
            typeof(int),
            typeof(TabbedExpander),
            new PropertyMetadata(96, OnMinHeightChanged));
    private static void OnMinHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        throw new NotImplementedException();
    }

    public static readonly DependencyProperty EXPANDER_MAX_HEIGHTProperty =
        DependencyProperty.Register("EXPANDER_MAX_HEIGHT",
            typeof(int),
            typeof(TabbedExpander),
            new PropertyMetadata(400, OnMaxHeightChanged));
    private static void OnMaxHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        throw new NotImplementedException();
    }

    public static readonly DependencyProperty EXPANDER_NOTEXPANDED_HEIGHTProperty =
        DependencyProperty.Register("EXPANDER_NOTEXPANDED_HEIGHT",
            typeof(int),
            typeof(TabbedExpander),
            new PropertyMetadata(30, OnNotExpandedHeightChanged));
    private static void OnNotExpandedHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        throw new NotImplementedException();
    }

    public static readonly DependencyProperty EXPANDER_EXPANDED_HEIGHTProperty =
        DependencyProperty.Register("EXPANDER_EXPANDED_HEIGHT",
            typeof(double),
            typeof(TabbedExpander),
            new PropertyMetadata(100d, OnExpandedHeightChanged));
    private static void OnExpandedHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        throw new NotImplementedException();
    }
    #endregion
    #endregion

    #region PropertyChanged
    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    protected void NotifyPropChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        this.Height = this.EXPANDER_NOTEXPANDED_HEIGHT;
    }
}

And a little MainWindow.xaml for testing:

<Window x:Class="PRUEBA_TABBEDEXPANDER.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:PRUEBA_TABBEDEXPANDER"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <local:TabbedExpander TabStripPlacement="Top">
            <TabItem Header="prueba1">
                <TextBox Text="prueba1"/>
            </TabItem>
    </local:TabbedExpander>
</Grid>

That's my last try, my first try was to apply the TabbedExpanderTabControlStyle style directly to the custom control just changing the TargetType , then i've tried without adding the ItemsSProperty , just using the TabControl 's inherited ItemsSource with the same syntax in the 'MainWindow.xaml`, and changing the syntax to:

<Grid>
    <local:TabbedExpander TabStripPlacement="Top">
        <local:TabbedExpander.ItemsS>
            <TabItem Header="prueba1">
                <TextBox Text="prueba1"/>
            </TabItem>
        </local:TabbedExpander.ItemsS>
    </local:TabbedExpander>
</Grid>

As well as <local:TabbedExpander.Items> trying to use the TabControl 's inherited Items .

The only thing that worked was to merge the Generic.xaml as a ResourceDictionary and apply TabbedExpanderTabControlStyle directly to the custom control... which I suppose is NOT the correct way to do it... right? Because i would have to apply the style to every custom control I would add to my application...

I suppose that either I'm doing something wrong applying the style, or using the tabitems collections, but right now I'm out of ideas :(
Any idea?

Normally you'd add your generic style to your window (or other high-level control) resource dictionary like this:

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Themes/Generic.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>

So that all child controls will inherit it. Have you tried that?

Note, now you've created a custom control you'll want to change the target type of your style and it will apply to all instances of your control in your application. (though looks like you've already thought of that)

If you are using this control elsewhere it might be worth having the style in it's own file, then other projects can include it in their own generic/windows resource directories. This is how wellknown libraries like MahhApps.Metro work, for example with their controls my generic.xaml might look like this:

<ResourceDictionary ...>
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
        ... other imported resource dictionaries
    </ResourceDictionary.MergedDictionaries>
   ...my application specific stuff...
</ResourceDictionary>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM