【问题标题】:Silverlight TabItem Visibility not changingSilverlight TabItem 可见性没有改变
【发布时间】:2012-04-07 05:04:40
【问题描述】:

我有一个 TabControl,其中有许多 TabItems 绑定到一个 ViewModel,该 ViewModel 具有每个 TabItem 的可见性的属性。

<sdk:TabControl>
    <sdk:TabItem Name="Inventory" Header="Inventory" 
        Style="{StaticResource TabItemStyle}"
        Visibility="{Binding Permissions.Inventory,
        Converter={StaticResource PermissiveVisibilityConverter}, 
            ConverterParameter='Viewer'}"
        DataContext="{Binding VM}" />

</sdk:TabControl>

所有 TabItems 默认为折叠的可见性。但是,当 VM 将 TabItem 更改为 Visible 时,它​​不会工作,直到您将鼠标移到控件上...

即使我使用按钮以编程方式设置可见性,它的行为也是一样的!

我检查了 VM 的属性是否正在通知 UI,并且它们与 NotifyOnPropertyChanged 一起使用。如果我将数据绑定到按钮的可见性,它就可以正常工作...只是 TabItems 似乎有错误。

有没有办法让 TabItem UI 刷新?或者解决这个问题?

谢谢!

【问题讨论】:

  • 您使用的是什么版本的 SL?通知属性是否同时更改了权限属性和库存属性?
  • Silverlight 5. 两者都是,我检查了当我更新 ViewModel 时 TabItem 是否看到了更改并且确实看到了更改。它只是不更新​​ UI。
  • 嗯嗯很奇怪!我知道选项卡控件确实有一些错误,但我不看自己唯一可以建议的是从 codeplex 下载工具包源代码并尝试查看选项卡控件是否在内部处理选项卡项的可见性?对不起,我没有一个简单的答案给你
  • CodePlex 工具包有一个 TabControl? O.o 我使用的是 Silverlight SDK 中提供的内置 TabControl。
  • 是同一个tab控件,但是下载工具包源码的时候会得到sdk源码。

标签: silverlight tabcontrol visibility silverlight-5.0 tabitem


【解决方案1】:

如果您更改 xaml 以便首先设置 DataContext 会怎样:

 <sdk:TabItem Name="Inventory" Header="Inventory" 
    Style="{StaticResource TabItemStyle}"
    DataContext="{Binding VM}"
    Visibility="{Binding Permissions.Inventory,
    Converter={StaticResource PermissiveVisibilityConverter}, 
        ConverterParameter='Viewer'}" />

我假设 Permissions.Inventory 是您的视图模型上的一个属性,但由于您当时尚未设置上下文,因此绑定似乎不起作用。

另外,如果您设置断点并且调用 Permissions.Inventory 上的 getter,您的转换器是否会被命中?

【讨论】:

  • 我在某处放置了一个按钮,并将其设置为在折叠和可见之间轻弹权限,它似乎无需移动要首先设置的数据上下文即可工作。该问题似乎仅在表单初始化时出现。
  • 如果我将其初始化为折叠状态,然后使用按钮将其设置为可见,则在您单击另一个选项卡之前它不起作用 - 然后它会弹出可见。但是下次你设置它时它会折叠然后重新显示它就可以正常工作。
【解决方案2】:

我遇到了同样的问题,我能够使用附加的“可见性”属性而不是原始属性来克服它。在这个新属性中,我可以将值传递给原始的“Visibility”属性,如果父选项卡控件的“SelectedItem”被折叠,请选择下一个可见的 tabItem。

但是,正如here 所述,如果在加载 TabControl 时折叠第一个项目,这可能还不够。这种情况必须在 TabControl 本身中修复,因为测试显示当第一次设置假的“可见性”时,TabItem 还没有访问它的 TabControl。因此,我还使用了 TabControl 的附加属性来纠正此问题。

完整的解决方案:

public static class TabControlExtensions
{
    /// <summary>
    /// Use this property on a TabControl to correct the behavior
    /// of selecting Collapsed TabItems.
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static bool GetSelectOnlyVisibleTabs(DependencyObject obj)
    {
        return (bool)obj.GetValue(SelectOnlyVisibleTabsProperty);
    }
    public static void SetSelectOnlyVisibleTabs(DependencyObject obj, bool value)
    {
        obj.SetValue(SelectOnlyVisibleTabsProperty, value);
    }
    public static readonly DependencyProperty SelectOnlyVisibleTabsProperty =
        DependencyProperty.RegisterAttached("SelectOnlyVisibleTabs", typeof(bool), typeof(TabControlExtensions), new PropertyMetadata(false, SelectOnlyVisibleTabsChanged));
    public static void SelectOnlyVisibleTabsChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var tabControl = sender as TabControl;
        if (tabControl == null) return;

        if ((bool)args.NewValue)
        {
            tabControl.SelectionChanged += TabControl_SelectionChanged;
            CorrectSelection(tabControl);
        }
        else
        {
            tabControl.SelectionChanged -= TabControl_SelectionChanged;
        }
    }

    private static void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs args)
    {
        var tabControl = sender as TabControl;
        if (tabControl == null) return;

        CorrectSelection(tabControl);
    }

    public static void CorrectSelection(TabControl tabControl)
    {
        var selected = tabControl.SelectedItem as UIElement;
        if (selected == null) return;

        // If the selected element is not suposed to be visible,
        // selects the next visible element
        if (selected.Visibility == System.Windows.Visibility.Collapsed)
            tabControl.SelectedItem = tabControl.Items.OfType<UIElement>()
                .Where(e => e.Visibility == System.Windows.Visibility.Visible)
                .FirstOrDefault();
    }
}

public static class TabItemExtensions
{
    /// <summary>
    /// Use this property in a TabItem instead of the original "Visibility" to 
    /// correct the behavior of a TabControl when a TabItem's Visibility changes.
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static Visibility GetVisibility(DependencyObject obj)
    {
        return (Visibility)obj.GetValue(VisibilityProperty);
    }
    public static void SetVisibility(DependencyObject obj, Visibility value)
    {
        obj.SetValue(VisibilityProperty, value);
    }
    public static readonly DependencyProperty VisibilityProperty =
        DependencyProperty.RegisterAttached("Visibility", typeof(Visibility), typeof(TabItemExtensions), new PropertyMetadata(Visibility.Visible, VisibilityChanged));

    public static void VisibilityChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var tabItem = sender as TabItem;
        if (tabItem == null) return;

        var visibility = (Visibility)args.NewValue;
        if (tabItem.Visibility == visibility) return;

        tabItem.Visibility = visibility;
        if (visibility == Visibility.Visible) return;

        // Finds the tab's parent tabcontrol and corrects the selected item, 
        // if necessary.
        var tabControl = tabItem.Ancestors().OfType<TabControl>().FirstOrDefault();
        if (tabControl == null) return;

        TabControlExtensions.CorrectSelection(tabControl);
    }
}

用法:

<sdk:TabControl local:TabControlExtensions.SelectOnlyVisibleTabs="True">
        <sdk:TabItem Header="tabItem1" Visibility="Collapsed">
            <TextBlock HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       Text="TabItem1 which should not be visible (1)" />
        </sdk:TabItem>
        <sdk:TabItem Header="tabItem2">
            <TextBlock HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       Text="TabItem2 which should be visible (2)" />
        </sdk:TabItem>
        <sdk:TabItem DataContext="{Binding ViewModel}"
                     Header="tabItem3"
                     local:TabItemExtensions.Visibility="{Binding MyProperty,
                                                                 Converter={StaticResource BoolToVisibilityConverter}}">
            <TextBlock HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       Text="TabItem with binded Visibility (3)" />
        </sdk:TabItem>
    </sdk:TabControl>

【讨论】:

  • 我还没有在我的项目中测试这个,但它看起来很可靠。谢谢你的工作:)
  • 所以我只是使用了这个并且遇到了一个问题,它根本没有任何效果。我需要做的一个小改动是为 TabControl 的 Loaded 事件添加一个事件处理程序。在全部加载之前,尚未设置所有可见性属性。
  • 感谢您的努力。但不得不在 VisibilityChanged 方法 tabItem.GetSelfAndAncestors().OfType().FirstOrDefault() 中将 Ancestors 修改为 GetSelfAndAncestors
猜你喜欢
  • 2011-11-08
  • 1970-01-01
  • 2011-04-10
  • 2017-04-29
  • 2016-11-28
  • 1970-01-01
  • 2012-03-07
  • 2021-07-19
  • 1970-01-01
相关资源
最近更新 更多