Question

I am having difficulty getting an attached property working on a WPF Tab Control. I have implemented the class defined in the CodeProject tutorial

http://www.codeproject.com/Articles/349140/WPF-TabControl-focus-behavior-with-invisible-tabs

defined below.

namespace MyNamespace 
{

public static class TabControlBehavior
{
    public static readonly DependencyProperty FocusFirstVisibleTabProperty =
        DependencyProperty.RegisterAttached("FocusFirstVisibleTab",
                                            typeof(bool),
                                            typeof(TabControlBehavior), 
                                            new FrameworkPropertyMetadata(OnFocusFirstVisibleTabPropertyChanged));

/// <summary>Gets the focus first visible tab value of the given element.

/// </summary>
/// <param name="element">The element.</param>
/// <returns></returns>

public static bool GetFocusFirstVisibleTab(TabControl element)
{
    if (element == null)
    {
        throw new ArgumentNullException("element");
    }
    return (bool)element.GetValue(FocusFirstVisibleTabProperty);
}

/// <summary>Sets the focus first visible tab value of the given element.

/// </summary>
/// <param name="element">The element.</param>
/// <param name="value">if set to <c>true</c> [value].</param>

public static void SetFocusFirstVisibleTab(TabControl element, bool value)
{
    if (element == null)
    {
        throw new ArgumentNullException("element");
    }
    element.SetValue(FocusFirstVisibleTabProperty, value);
}

/// <summary>Determines whether the value of the dependency property <c>IsFocused</c> has change.
/// </summary>
/// <param name="d">The dependency object.</param>
/// <param name="e">The <see
///   cref="System.Windows.DependencyPropertyChangedEventArgs"/>
///   instance containing the event data.</param>
private static void OnFocusFirstVisibleTabPropertyChanged(
    DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var tabControl = d as TabControl;
    if (tabControl != null)
    {
        // Attach or detach the event handlers.

        if ((bool)e.NewValue)
        {
            // Enable the attached behavior.
            tabControl.Items.CurrentChanged += new EventHandler(TabControl_Items_CurrentChanged);
            var collection = tabControl.Items as INotifyCollectionChanged;
            if (collection != null)
            {
                collection.CollectionChanged += 
                    new NotifyCollectionChangedEventHandler(TabControl_Items_CollectionChanged);
            }
        }
        else

        {
            // Disable the attached behavior.
            tabControl.Items.CurrentChanged -= new EventHandler(TabControl_Items_CurrentChanged);
            var collection = tabControl.Items as INotifyCollectionChanged;
            if (collection != null)
            {
                collection.CollectionChanged -= 
                    new NotifyCollectionChangedEventHandler(TabControl_Items_CollectionChanged);
            }
            // Detach handlers from the tab items.

            foreach (var item in tabControl.Items)
            {
                TabItem tab = item as TabItem;
                if (tab != null)
                {
                    tab.IsVisibleChanged -= 
                        new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                }
            }
        }
    }
}

/// <summary>Handles the CollectionChanged event of the TabControl.Items collection.
/// </summary>
/// <param name="sender">The source of the event.</param>

/// <param name="e">The <see
///    cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs"/>
///    instance containing the event data.</param>

static void TabControl_Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    // Attach event handlers to each tab so that when the Visibility property changes of the selected tab,
    // the focus can be shifted to the next (or previous, if not next tab available) tab.
    var collection = sender as ItemCollection;
    if (collection != null)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
            case NotifyCollectionChangedAction.Remove:
            case NotifyCollectionChangedAction.Replace:
                // Attach event handlers to the Visibility and IsEnabled properties.

                if (e.NewItems != null)
                {
                    foreach (var item in e.NewItems)
                    {
                        TabItem tab = item as TabItem;
                        if (tab != null)
                        {
                            tab.IsVisibleChanged += 
                                new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                        }
                    }
                }
                // Detach event handlers from old items.

                if (e.OldItems != null)
                {
                    foreach (var item in e.OldItems)
                    {
                        TabItem tab = item as TabItem;
                        if (tab != null)
                        {
                            tab.IsVisibleChanged -= 
                                new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                        }
                    }
                }
                break;
            case NotifyCollectionChangedAction.Reset:
                // Attach event handlers to the Visibility and IsEnabled properties.

                foreach (var item in collection)
                {
                    TabItem tab = item as TabItem;
                    if (tab != null)
                    {
                        tab.IsVisibleChanged += 
                            new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                    }
                }
                break;
            case NotifyCollectionChangedAction.Move:
            default:
                break;
        }

        // Select the first element if necessary.

        if (collection.Count > 0 && collection.CurrentItem == null)
        {
            collection.MoveCurrentToFirst();
        }
    }
}

/// <summary>Handles the CurrentChanged event of the TabControl.Items collection.
/// </summary>
/// <param name="sender">The source of the event.</param>

/// <param name="e">The <see cref="System.EventArgs"/>
/// instance containing the event data.</param>

static void TabControl_Items_CurrentChanged(object sender, EventArgs e)
{
    var collection = sender as ItemCollection;
    if (collection != null)
    {
        UIElement element = collection.CurrentItem as UIElement;
        if (element != null && element.Visibility != Visibility.Visible)
        {
            element.Dispatcher.BeginInvoke(new Action(() => collection.MoveCurrentToNext()), 
                                           System.Windows.Threading.DispatcherPriority.Input);
        }
    }
}


/// <summary>Handles the IsVisibleChanged event of the tab item.
/// </summary>
/// <param name="sender">The source of the event.</param>

/// <param name="e">The <see
///   cref="System.Windows.DependencyPropertyChangedEventArgs"/>
///   instance containing the event data.</param>

static void TabItem_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    TabItem tab = sender as TabItem;
    if (tab != null && tab.IsSelected && tab.Visibility != Visibility.Visible)
    {
        // Move to the next tab item.

        TabControl tabControl = tab.Parent as TabControl;
        if (tabControl != null)
        {
            if (!tabControl.Items.MoveCurrentToNext())
            {
                // Could not move to next, try previous.
                tabControl.Items.MoveCurrentToPrevious();
            }
        }
    }
}
}
}

I then try to set the attached dependency property in my xaml code as follows :

<Window x:Class="MyNamespace.MyApp"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d3="http://research.microsoft.com/DynamicDataDisplay/1.0"
        xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
        xmlns:local="clr-namespace:MyNamespace">

    <Window.Resources>
        <ResourceDictionary>
            <Style TargetType="{x:Type TabControl}">
                <Setter Property="local:TabControlBehavior.FocusFirstVisibleTab" Value="True" />
            </Style>
        </ResourceDictionary>
    </Window.Resources>
</Window>

However I can't compile due to the following error

MC4003: Cannot resolve the Style Property 'FocusFirstVisibleTab'. Verify that the owning type is the Style's TargetType, or use Class.Property syntax to specify the Property.

Thanks in advance for any help.

Was it helpful?

Solution

The problem was resolved by renaming MyNamespace to something other than the namespace containing my application.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top