WPF - TabItem 中奇怪的滚动条行为

发布于 2024-09-29 03:07:53 字数 1458 浏览 0 评论 0原文

我有以下代码:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="145" Width="156">
    <Window.Resources>
        <DataTemplate x:Key="tabTemplate">
            <ScrollViewer>
                <StackPanel Orientation="Vertical">
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                </StackPanel>
            </ScrollViewer>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <TabControl>
            <TabItem Header="Tab1" ContentTemplate="{StaticResource ResourceKey=tabTemplate}"/>
            <TabItem Header="Tab2" ContentTemplate="{StaticResource ResourceKey=tabTemplate}"/>
        </TabControl>
    </Grid>
</Window>

奇怪的是滚动条的行为 - 如果我在第一个选项卡上向下滚动并切换到第二个选项卡,滚动条也会向下 - 当选项卡项具有相同的数据模板时,滚动条的位置会同步。您知道这个问题有什么解决方案吗?

此外,当我更改代码并制作两个数据模板(每个选项卡一个)时,滚动条根本不保留其位置 - 这意味着如果我在 tab1 上向下滚动,切换到 tab2 并再次切换到 tab1,滚动条将在默认位置。这个有什么解决办法吗?

I have following code:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="145" Width="156">
    <Window.Resources>
        <DataTemplate x:Key="tabTemplate">
            <ScrollViewer>
                <StackPanel Orientation="Vertical">
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                </StackPanel>
            </ScrollViewer>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <TabControl>
            <TabItem Header="Tab1" ContentTemplate="{StaticResource ResourceKey=tabTemplate}"/>
            <TabItem Header="Tab2" ContentTemplate="{StaticResource ResourceKey=tabTemplate}"/>
        </TabControl>
    </Grid>
</Window>

What is weird is the behavior of scrollbars - if I scroll down on the first tab and switch to second tab, the scrollbar is down too - position of the scrollbars is synchronized when the tab items have the same data templates. Do you know about any solution of this issue?

In addition, when I alter the code and make two data templates (one for each tab), the scrollbars are not preserving their position at all - that means if I scroll down on tab1, switch to tab2 and to tab1 again, the scrollbar is on default position. Any solution of this one?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

固执像三岁 2024-10-06 03:07:53

要使 DataTemplate 能够为每次使用创建单独的实例,只需将 x:Shared 属性设置为 False

<DataTemplate x:Key="tabTemplate" x:Shared="False">

这将导致您的第二个问题,当选项卡更改时,它会保留 UI。根据 TabControl 中的 WPF UI 持久性,解决方案是使用不同的 ItemsControl,它看起来像TabControl

To enable the DataTemplate to create separate instances for each usage, just set the x:Shared attribute to False:

<DataTemplate x:Key="tabTemplate" x:Shared="False">

That will cause your second issue, which is preserving the UI when the tab changes. According to WPF UI persistence in TabControl, the solution would be to use a different ItemsControl that looks like a TabControl.

风尘浪孓 2024-10-06 03:07:53

我使用新控件 ZoomPanel : ScrollViewer 解决了第二个问题,其中滚动条的位置根据 DataContext.GetHashCode() 保存。也许不是最佳解决方案,但对我有用。每个选项卡都有自己的 ViewModel,因此滚动条的位置会被保留。

public static readonly Dictionary<int, Point> ScrollbarPositions = new Dictionary<int, Point>();

private void ZoomPanelScrollChanged(object sender, ScrollChangedEventArgs e)
{
    ZoomPanel panel = (ZoomPanel)sender;

    // do not save position when uloading or empty data context
    if(!panel.IsLoaded || this.DataContext == null)
    {
        return;
    }

    // save scrollbar position
    int dataContextHashCode = this.DataContext.GetHashCode();
    Point position = new Point(panel.HorizontalOffset, panel.VerticalOffset);

    if(ScrollbarPositions.ContainsKey(dataContextHashCode))
    {
        ScrollbarPositions[dataContextHashCode] = position;
    }
    else
    {
        ScrollbarPositions.Add(dataContextHashCode, position);
    }
}

private void ZoomPanelLoaded(object sender, RoutedEventArgs e)
{
    if(this.DataContext == null)
    {
        return;
    }

    // load scrollbar position
    int dataContextHashCode = this.DataContext.GetHashCode();
    if (ScrollbarPositions.ContainsKey(dataContextHashCode))
    {
        Point position = ScrollbarPositions[dataContextHashCode];
        this.ScrollToHorizontalOffset(position.X);
        this.ScrollToVerticalOffset(position.Y);
    }
}

I solved the second issue using new control ZoomPanel : ScrollViewer, where the position of scollbars is saved according to DataContext.GetHashCode(). Maybe not optimal solution, but works for me. Every tab has its own ViewModel, so the position of scrollbars is preserved.

public static readonly Dictionary<int, Point> ScrollbarPositions = new Dictionary<int, Point>();

private void ZoomPanelScrollChanged(object sender, ScrollChangedEventArgs e)
{
    ZoomPanel panel = (ZoomPanel)sender;

    // do not save position when uloading or empty data context
    if(!panel.IsLoaded || this.DataContext == null)
    {
        return;
    }

    // save scrollbar position
    int dataContextHashCode = this.DataContext.GetHashCode();
    Point position = new Point(panel.HorizontalOffset, panel.VerticalOffset);

    if(ScrollbarPositions.ContainsKey(dataContextHashCode))
    {
        ScrollbarPositions[dataContextHashCode] = position;
    }
    else
    {
        ScrollbarPositions.Add(dataContextHashCode, position);
    }
}

private void ZoomPanelLoaded(object sender, RoutedEventArgs e)
{
    if(this.DataContext == null)
    {
        return;
    }

    // load scrollbar position
    int dataContextHashCode = this.DataContext.GetHashCode();
    if (ScrollbarPositions.ContainsKey(dataContextHashCode))
    {
        Point position = ScrollbarPositions[dataContextHashCode];
        this.ScrollToHorizontalOffset(position.X);
        this.ScrollToVerticalOffset(position.Y);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文