Silverlight TabControl-在TabItem中从给定控件中查找和选择TabItem

Silverlight TabControl-在TabItem中从给定控件中查找和选择TabItem,silverlight,tabcontrol,tabitem,Silverlight,Tabcontrol,Tabitem,我正在构建一个LOB应用程序,它有一个main部分和一个TabControl,其中包含各种TabItems。点击save时,任何出错的字段都会突出显示,第一个出错的字段会获得焦点 如果第一个(也是唯一一个)错误字段位于未选中的选项卡上,则该选项卡应处于选中状态,并且错误字段应高亮显示并具有焦点。但是我不能让它工作 似乎发生的情况是,未选择的选项卡不在可视化树中,因此您无法导航回所属的TabItem并使其成为TabControl中当前选定的TabItem 有人知道如何做到这一点吗?我知道一种方法,

我正在构建一个LOB应用程序,它有一个main部分和一个TabControl,其中包含各种TabItems。点击save时,任何出错的字段都会突出显示,第一个出错的字段会获得焦点

如果第一个(也是唯一一个)错误字段位于未选中的选项卡上,则该选项卡应处于选中状态,并且错误字段应高亮显示并具有焦点。但是我不能让它工作

似乎发生的情况是,未选择的选项卡不在可视化树中,因此您无法导航回所属的TabItem并使其成为TabControl中当前选定的TabItem


有人知道如何做到这一点吗?

我知道一种方法,但很难看。它涉及使用间隔为几毫秒的Dispatcher。在加载的页面中,您将启动计时器。然后在每个勾号上为其中一个选项卡项设置IsSelected=true。在下一个勾号上,它选择下一个选项卡项目等,直到所有选项卡都被选中。然后,您必须再次选择第一项并关闭计时器。这将强制加载选项卡项目中的视觉效果

在此操作期间,您还必须用边框或其他东西覆盖TabControl。否则,用户将看到所有选项卡项快速掠过

我是如何解决的(通过询问首席架构师)

用一个方法Activate创建接口ITabActivator

创建一个从Grid和ITabActivator派生的类,称为TabPageActivator。其构造函数接受TabITem和TabControl

不要向TabItem.Contents添加简单的网格,而是添加一个TabPageActivator

将父检测更改为使用

DependencyObject parent=\u Control.parent

…而不是使用VisualTreeHelper

因此,当您浏览层次结构测试时

if(父项为TabActivator) (父项作为ITabActivator)。激活()

。。。那么什么时候调用Activate

m_TabControl.SelectedItem=m_TabItem;//从构造函数参数


…别忘了你可能有嵌套的选项卡,所以你需要不断地升级层次结构。

我在我的一个站点上使用TabControls进行导航(),并构建了一些扩展方法,帮助我使用标记名选择选项卡。下面是一些应该适合您的代码片段

扩展类:

using System;
using System.Linq;
using System.Windows.Controls;

namespace MyApplication
{
    internal static class Extensions
    {
        // Extension for TabControl
        internal static void SelectTab(this TabControl tabControl, this TabItem tabItem)
        {
            if (tabControl == null || tabItem == null)
                return null;

            SelectTab(tabControl, tabItem.Tag);
        }

        // Extension for TabControl
        internal static void SelectTab(this TabControl tabControl, string tabTagName)
        {
            if (tabControl == null)
                return null;

            // Find the TabItem by its Tag name
            TabItem mainTabItem = tabControl.FindByTag(tabTagName);
            if (mainTabItem == null)
                return;

            // Check to see if the tab needs to be selected
            if (tabControl.SelectedItem != mainTabItem)
                tabControl.SelectedItem = mainTabItem;
        }

        // Extension for TabControl
        internal static TabItem FindByTag(this TabControl tabControl, string tagFragment)
        {
            if (tabControl == null || tagFragment == null)
                return null;

            return tabControl.Items
                    .OfType<TabItem>()
                    .Where(item => item.Tag != null && item.Tag.ToString().StartsWithIgnoreCase(tagFragment))
                    .FirstOrDefault();
        }

        // Extension for string
        internal static bool StartsWithIgnoreCase(this string source, string target)
        {
            return source.StartsWith(target, StringComparison.CurrentCultureIgnoreCase);
        }
    }
}
<Controls:TabControl x:Name="x_TabControl">
    <Controls:TabItem Header="Welcome" Tag="/Home/Welcome" x:Name="x_WelcomeTab" />
    <Controls:TabItem Header="FAQ" Tag="/Home/FAQ" />
    <Controls:TabItem Header="Contact Us" Tag="/Home/Contact_Us" />
    <Controls:TabItem Header="Privacy Policy" Tag="/Home/Privacy_Policy" />
    <Controls:TabItem Header="My Account" Tag="/Home/My_Account" />
</Controls:TabControl>
x_TabControl.SelectTab("/Home/Welcome");  

要加载选项卡项,请执行以下操作:

tabControl.SelectedItem = tabItemOfInterest;
tabControl.UpdateLayout();
这将导致tabItemOfInterest与TabItem中包含的所有控件一起加载

仅下一行不会加载选项卡ItemOfInterest:

tabControl.SelectedItem = tabItemOfInterest;

然而,我对David为获得错误控件而采用的方法非常感兴趣。

我使用附加属性TabItem的解决方案。 创建类TabItemExtender:

/// <summary>
/// TabItem Extender class with TabItem property
/// </summary>
public class TabItemExtender
{
    #region property getters/setters
    /// <summary>
    /// TabItem attached dependency property
    /// </summary>
    public static readonly DependencyProperty TabItemProperty = DependencyProperty.RegisterAttached("TabItem", typeof(TabItem), typeof(TabItemExtender), null);

    /// <summary>
    /// TabItem Property getter
    /// </summary>
    public static TabItem GetNavigateUri(DependencyObject source)
    {
        return (TabItem)source.GetValue(TabItemExtender.TabItemProperty);
    }

    /// <summary>
    /// TabItem Property setter
    /// </summary>
    public static void SetNavigateUri(DependencyObject target, TabItem value)
    {
        target.SetValue(TabItemExtender.TabItemProperty, value);
    }
    #endregion
}
在设置焦点之前:

var element = (UIElement)control;
while (element != null)
{
    //Get TabItem
    var tabItem = (TabItem)element.GetValue(TabItemExtender.TabItemProperty);

    if (tabItem != null)
    {
        if (!tabItem.IsSelected && tabItem.IsEnabled)
        {
            tabItem.IsSelected = true;
            ((TabControl)tabItem.Parent).UpdateLayout();
        }

        break;
    }

    element = (UIElement)VisualTreeHelper.GetParent(element);
}

control.Focus();

是的,这不是一个很好的解决方案。我自己使用这个解决方案,每次看到代码时都会感到畏缩如果我再做一次,我会把它封装在一个行为中,让它消失在视线之外。不幸的是,我想不出另一种方式来渲染视觉效果。问题是根据将在其中显示的控件查找要选择的选项卡项。在最终的验证选项卡显示之前,您肯定看到每个选项卡都先被选中了吗?不,没有,它工作正常。我对解决方案的解释可能有点过于简短。如果您愿意的话,我可以更详细地解释一下?小挑剔:我发现在控件上使用非默认构造函数是一个非常糟糕的主意。它使控件非xaml友好。。。
private void ExtendedTabControl_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
    foreach (object item in this.Items)
    {
        var tabItem = item as TabItem;
        if (tabItem != null && tabItem.Content != null)
        {
            var element = (FrameworkElement)tabItem.Content;
            element.SetValue(TabItemExtender.TabItemProperty, tabItem);
        }
    }
}
var element = (UIElement)control;
while (element != null)
{
    //Get TabItem
    var tabItem = (TabItem)element.GetValue(TabItemExtender.TabItemProperty);

    if (tabItem != null)
    {
        if (!tabItem.IsSelected && tabItem.IsEnabled)
        {
            tabItem.IsSelected = true;
            ((TabControl)tabItem.Parent).UpdateLayout();
        }

        break;
    }

    element = (UIElement)VisualTreeHelper.GetParent(element);
}

control.Focus();