TabControl缓存,布局更改后带有代码

时间:2019-01-15 11:50:03

标签: c# wpf tabcontrol

关于此问题here,是否可以从后面的代码中更新其他选项卡内容,并允许缓存允许重新缓存已更改的UI元素?就像在场景中,在某些事件中,DataGrid上的tabs的{​​{1}}的滚动索引已更新,

TabControl

现在,由于选项卡已被缓存,并且当用户切换到dgvLogs.ScrollIntoView( log ); 所在的选项卡时,以上更改都不会反映出来。

编辑

我在主窗口中具有选项卡控件(dgvLogs),并且具有多个包含ExTabControl的选项卡,它们在其中显示了一些应用程序日志。像这样:

datagrid像这样:

ExTabControl

单个标签具有如下所示的数据网格:

<controls:ExTabControl Grid.Row="1" ItemsSource="{Binding Tabs, Mode=OneWay}" >
            <controls:ExTabControl.Resources>
                <Style TargetType="{x:Type TabItem}">

                </Style>
            </controls:ExTabControl.Resources>
</controls:ExTabControl>

问题:

假设我在<DataGrid Name="dgvLogs" ItemsSource="{Binding Logs}" VerticalScrollBarVisibility="Auto" FrozenColumnCount="4"> 中有3个标签,选择的标签是1,并且从后面的代码中使用ExTabControl的标签2有更新的滚动索引。理想情况下,如果我确实选择选项卡2,则选择dgvLogs.ScrollIntoView( someInbetweenlog );内的滚动索引应该位于dgvLogs的位置。但是不幸的是,选项卡2的滚动不会根据所做的更改而移动。

如果我确实使用默认的标签控件,即someInbetweenlog插入了TabControl,则它可以正常工作。但是如果我将滚动移动到ExTabControl的任何标签中,那么它也会反映在其他标签中。.

请添加注释,如有需要,我会发布更多代码。

编辑2

我创建了示例应用程序,试图在其中演示该问题。在这个应用程序中,我在选项卡中添加了用于网格的上下文菜单,并使用dgvLogs选项试图滚动查看在其他打开的选项卡中找到的第一个与关闭的选定日志匹配的日志。

问题:Sync无法滚动到其他打开的选项卡中的所需日志项目。

https://github.com/ankushmadankar/StackOverflow54198246/

2 个答案:

答案 0 :(得分:2)

  

如果我做化妆使用默认选项卡控制的,即TabControl如预期代替ExTabControl,则它工作正常。但是,如果我移动滚动任何分页为dgvLogs,然后它被反射在其他选项卡还

有两种用途TabControl,上延伸this post

  1. 当我们将ItemsSource绑定到项目列表时,并且我们为每个项目设置了相同的DataTemplateTabControl将为所有项目仅创建一个“内容”视图。而且,当选择其他选项卡项目时,View不会改变,但后盾DataContext绑定到新选择的项目的视图模型。
  

是否有可能更新从代码后面其它选项卡内容,并让缓存允许重新缓存改变UI元素?

究其原因,更新将不会工作是因为另一个WPF优化,从UIElement.IsVisible

  

IsVisible为假的元素不参与输入事件(或命令),不影响布局的度量或排列通过,不集中,不在制表符序列中,并且不会在命中测试中报告

您可以更改缓存元素的属性,但是某些操作要求可见UIElement才能生效。

值得注意的是:

  • 如果你调用{{1}在ScrollIntoView这是不可见的,它不会滚动到给定的对象。所以DataGrid从你的链接项目的目的是滚动数据网格的过程中是可见的。
  • 在的代码ScrollToSelectedBehavior该方法ExTabControl,使非活性contentpresenters到折叠的可见性。

鉴于您已经明确要求在后面提供代码,

快速攻克

TraceViewerView.xaml

UpdateSelectedItem

TraceViewerView.xaml.cs

<DataGrid IsVisibleChanged="dgvLogs_IsVisibleChanged" ... >

几句话:

  • 现在,可以删除行private void dgvLogs_IsVisibleChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e) { if (sender is DataGrid dataGrid && dataGrid.IsVisible) { TraceViewerViewModel viewModel = (TraceViewerViewModel)DataContext; if (viewModel.Log != null) dataGrid.ScrollIntoView(viewModel.Log); } } ,因为我们直接从视图模型获取同步值。
  • 这是一个 hack,该视图已硬编码到您的视图模型中,有时可能会崩溃。

:一种更好的方法

首先,为了保持我们的代码松散耦合,一个接口。

local:ScrollToSelectedBehavior.SelectedValue="{Binding Log}"

TraceViewerModel.cs

interface ISync
{
    object SyncValue { get; }
}

重命名public class TraceViewerViewModel : PropertyObservable, ITabItem, ISync Log,并替换原始代码

SyncValue

使用

private TraceLog synclog;
public TraceLog Log
{
    get { return synclog; }
    private set
    {
        synclog = value;

        OnPropertyChanged();
    }
}

基本上,我们在public object SyncValue { get; set; } 交易来的接口。我之所以在此特定用例中使用该界面,是因为您仅需在移至该选项卡时检查该选项卡的同步值(使Binding完全成熟就显得有些过分)。

接下来,让我们创建一个Binding,你想要做什么。

我将使用交互行为,而不是附加属性,该行为提供了更封装的功能扩展方式(requires System.Windows.Interactivity)。

ScrollToSyncValueBehavior.cs

Behavior

TraceViewerView.xaml

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace WpfApp1
{
    public class ScrollToSyncValueBehavior : Behavior<DataGrid>
    {
        protected override void OnAttached()
        {
            this.AssociatedObject.IsVisibleChanged += OnVisibleChanged;
        }

        protected override void OnDetaching()
        {
            this.AssociatedObject.IsVisibleChanged -= OnVisibleChanged;
        }

        private static void OnVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender is DataGrid dataGrid && dataGrid.IsVisible)
            {
                ISync viewModel = dataGrid.DataContext as ISync;
                if (viewModel?.SyncValue != null)
                    dataGrid.ScrollIntoView(viewModel.SyncValue);
            }
        }
    }
}

答案 1 :(得分:1)

您需要按照this答案中的描述导出TabControl。使用该技术,将保留每个选项卡的可视树。

请注意,如果您有许多选项卡,则缓存将对性能产生重大影响。我建议最多将其用于10个标签。