简体   繁体   English

ScrollViewer ChangeView上SizeChanged

[英]ScrollViewer ChangeView on SizeChanged

I have DataTemplate which I use in HubSection: DataTemplate我在HubSection使用:

<DataTemplate x:Name="dataTemplate2">
    <Grid x:Name="greedy">
        <ScrollViewer x:Name="scroller" SizeChanged="ScrollViewer_SizeChanged" Height="{Binding Height,ElementName=greedy}" >
            <ItemsControl x:Name="itemsControl" 
                ItemsSource="{Binding}" 
                ItemTemplate="{StaticResource dataTemplateDetails}">
                <ItemsControl.ItemContainerTransitions>
                    <TransitionCollection>
                        <ReorderThemeTransition />
                        <NavigationThemeTransition />
                    </TransitionCollection>
                </ItemsControl.ItemContainerTransitions>
            </ItemsControl>
        </ScrollViewer>
    </Grid>
</DataTemplate>

In my ItemsControl I have items which can be expandable. 在我的ItemsControl我有一些可以扩展的项目。 What I want to achieve is that when the item will expand to see more details about that item. 我要实现的是,当该项目将展开以查看有关该项目的更多详细信息时。 I want Scrollviewer to scroll down (for amount of changed size of ScrollViewer ). 我希望Scrollviewer向下滚动(以获取ScrollViewer的更改大小)。

Code behind for SizeChanged event: SizeChanged事件的代码后面:

private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
{
     ScrollViewer myScroll = (ScrollViewer)sender;
     myScroll.ChangeView(null, myScroll.ScrollableHeight, null, false);
}

What I have done now is not working as my expectation. 我现在所做的工作没有达到我的期望。 I scroll down to the end right now. 我现在向下滚动到结尾。 But the thing is it scrolls only when the items extend the size of available view (ScrollBar is shown). 但问题是,只有当项目扩展了可用视图的大小时,它才会滚动(显示ScrollBar)。 Then if I expand another item it doesn't work. 然后,如果我展开另一个项目,它将不起作用。 If I hide details about item (ScrollBar hides too) and expand it again it will work again. 如果我隐藏有关项目的详细信息(ScrollBar也隐藏)并再次展开它,它将再次起作用。 It's like the SizeChanged event occures only when ScrollViewer is going into action but have infinite height which doesn't change. 就像SizeChanged事件仅在ScrollViewer付诸行动时发生,但是具有无限的高度不会改变。

I've tried Grid with row set to "*", it changes nothing. 我试过将行设置为“ *”的网格,它什么都不会改变。 Now I try to set height by binding it to height of ItemsControl - still the same behaviour. 现在,我尝试通过将其绑定到ItemsControl高度来设置高度-仍然是相同的行为。

Could you help me with the solution, show the path of thinking or enlighten me with some workaround? 您能为我提供解决方案,显示思路或通过一些变通方法启发我吗?

EDIT: 编辑:

I prepared some code to work with to see what happens exactly. 我准备了一些可使用的代码,以查看发生了什么。

1) Create New Project -> Store Apps (c#) -> Windows Phone 8.1 (Blank App) and name it "scroll" 1)创建新项目->商店应用(c#)-> Windows Phone 8.1(空白应用)并将其命名为“滚动”

2) Paste this code into MainPage.xaml 2)将此代码粘贴到MainPage.xaml中

<Page
x:Class="scroll.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:scroll"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="DarkOliveGreen">

<Page.Resources>
    <DataTemplate x:Name="dataTemplateDetails">
        <Grid Name="grido" Grid.Row="1" Margin="10,10,10,10">
            <Grid.RowDefinitions>
                <RowDefinition Height="50" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="50" />
                <RowDefinition Height="50" />
            </Grid.RowDefinitions>
            <Border Grid.Row="0" Background="Black" CornerRadius="10" Opacity="0.4" />
            <Border Grid.Row="1" Background="Black" CornerRadius="10" Opacity="0.3" />
            <Border Grid.Row="2" Background="Black" CornerRadius="10" Opacity="0.2" />
            <Border Grid.Row="3" Background="Black" CornerRadius="10" Opacity="0.1" />
            <TextBlock Grid.Row="0" Text="{Binding Name}" Style="{StaticResource BaseTextBlockStyle}" HorizontalAlignment="Center"/>
            <Grid Grid.Row="1" HorizontalAlignment="Center">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Margin="5,0,5,0" Text="Description:" Style="{StaticResource BaseTextBlockStyle}"/>
                <TextBlock Grid.Column="1" Text="{Binding Description}" Style="{StaticResource BaseTextBlockStyle}"/>
            </Grid>
            <TextBlock Grid.Row="2" Text="Next row" Style="{StaticResource BaseTextBlockStyle}" HorizontalAlignment="Center"/>
            <TextBlock Grid.Row="3" Text="Next row" Style="{StaticResource BaseTextBlockStyle}" HorizontalAlignment="Center"/>
        </Grid>
    </DataTemplate>
    <DataTemplate x:Name="dataTemplate2">
        <Grid x:Name="greedy" >
            <ScrollViewer x:Name="scroller" SizeChanged="ScrollViewer_SizeChanged" VerticalAlignment="Top">
                <ItemsControl x:Name="itemsControl" 
                    ItemsSource="{Binding}" 
                    ItemTemplate="{StaticResource dataTemplateDetails}">
                    <ItemsControl.ItemContainerTransitions>
                        <TransitionCollection>
                            <ReorderThemeTransition />
                            <NavigationThemeTransition />
                        </TransitionCollection>
                    </ItemsControl.ItemContainerTransitions>
                </ItemsControl>
            </ScrollViewer>
        </Grid>
    </DataTemplate>
</Page.Resources>

<Page.BottomAppBar>
    <CommandBar Background="Black" Opacity="0.6" x:Name="myCommandBar">
        <AppBarButton Icon="Add" Label="Add" x:Name="AddItem" Click="Add_Click"/>
        <AppBarButton Icon="Delete" Label="Delete" x:Name="RemoveItem" Click="Delete_Click"/>
    </CommandBar>
</Page.BottomAppBar>
<Grid>
    <Hub x:Name="myHub" Header="Test">
        <HubSection x:Uid="myDetailsHubsection" x:Name="myDetailsHubsection" Header="Details" DataContext="{Binding Items}" ContentTemplate="{StaticResource dataTemplate2}" />
    </Hub>
</Grid>

3) Paste this code into MainPage.xaml.cs 3)将此代码粘贴到MainPage.xaml.cs中

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace scroll
{
public sealed partial class MainPage : Page
{
    public static Details dataContextItems;

    public MainPage()
    {
        this.InitializeComponent();

        this.NavigationCacheMode = NavigationCacheMode.Required;

        dataContextItems = new Details();
    }

    public class TestItem
    {
        public string Name { get; set; }
        public string Description { get; set; }

        public TestItem(string n, string d)
        {
            Name = n;
            Description = d;
        }
    }

    public class Details : INotifyPropertyChanged
    {
        private ObservableCollection<TestItem> _items;
        public ObservableCollection<TestItem> Items
        {
            set
            {
                _items = value;
                NotifyPropertyChanged("Items");
            }
            get
            {
                return _items;
            }
        }

        public Details()
        {
            _items = new ObservableCollection<TestItem>();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        this.DataContext = dataContextItems;
    }

    private void Add_Click(object sender, RoutedEventArgs e)
    {
        TestItem iAmAnItem = new TestItem("Name of an item", "Long and detailed description of an item");
        dataContextItems.Items.Add(iAmAnItem);
    }

    private void Delete_Click(object sender, RoutedEventArgs e)
    {
        if (dataContextItems.Items.Count > 0)
            dataContextItems.Items.RemoveAt(0);
    }

    private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        ScrollViewer myScroll = (ScrollViewer)sender;
        myScroll.ChangeView(null, myScroll.ScrollableHeight, null, false);
    }
}
}

4) Run the app 4)运行应用

5) When you add first two items you can't scroll them but when you add more items you can see that it scrolls down as soon as items "need more space" to be shown and scrollbar occures. 5)当您添加前两个项目时,您无法滚动它们,但是当您添加更多项目时,您会看到,一旦显示项目“需要更多空间”并且出现滚动条,它就会向下滚动。 But with adding more items it doesn't work. 但是添加更多项目将无法正常工作。 If you delete items and add "third" item again it will scroll down. 如果删除项目并再次添加“第三”项目,它将向下滚动。

I want it to scroll down everytime size of scrollviewer changes (in this case when new item occures but keep in mind it should work when item "extends" in my original solution and there can be few extended items simultaneously). 我希望它每次滚动查看器大小更改时都向下滚动(在这种情况下,当新项目出现时,但请记住,当我的原始解决方案中的项目“扩展”并且同时可以有很少的扩展项目时,它应该工作)。

I've been tinkering with the solution and I finally found a way to do that. 我一直在研究解决方案,终于找到了一种解决方案。 I think the problem is that I didn't understand how ScrollViewer does work. 我认为问题是我不了解ScrollViewer工作方式。 I took the scrolling height as UIElement height hoping for SizeChanged to be fired what isn't truth. 我将滚动高度作为UIElement高度,希望触发SizeChanged这不是事实。 ScrollViewer wasn't changing its size because it just took the whole space it could and then just displayed how much content it is in it (It's like ScrollViewer has almost always infinite height unless it's less than actual available view space). ScrollViewer不会更改其大小,因为它只占用了可能的全部空间,然后仅显示其中的内容(就像ScrollViewer几乎总是无限高,除非它小于实际可用的视图空间)。 With adding first two items SizeChanged event was firing with third one too and then nothing happend. 通过添加前两个项目, SizeChanged事件也与第三个事件一起触发,然后什么也没有发生。 It proves that. 证明了这一点。

I needed SizeChanged to be fired everytime the size of ScrollViewer (or in this case the Grid ) was changing. 每当ScrollViewer (或本例中为Grid )的大小更改时,我都需要SizeChanged Solution is very simple but still it needs understanding of how ScrollViewer works - and now it seems so obvious that it will never be greater than available space. 解决方案非常简单,但是仍然需要了解ScrollViewer工作原理-现在看来如此明显,以至于它永远不会超过可用空间。

Changes made to make it work: 为使其正常运行而进行的更改:

<DataTemplate x:Name="dataTemplate2">
<ScrollViewer x:Name="scroller" VerticalAlignment="Top" HorizontalAlignment="Stretch" IsEnabled="True" >
    <Grid VerticalAlignment="Top" x:Name="greedo" SizeChanged="greedo_SizeChanged">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <ItemsControl x:Name="itemsControl" 
                    ItemsSource="{Binding}" 
                    ItemTemplate="{StaticResource dataTemplateDetails}">
                <ItemsControl.ItemContainerTransitions>
                    <TransitionCollection>
                        <ReorderThemeTransition />
                        <NavigationThemeTransition />
                    </TransitionCollection>
                </ItemsControl.ItemContainerTransitions>
            </ItemsControl>
        </Grid>
    </ScrollViewer>
</DataTemplate>

and code behind: 和后面的代码:

private void greedo_SizeChanged(object sender, SizeChangedEventArgs e)
{
        Grid takingScroll = (Grid)sender;
        ScrollViewer myScroll = (ScrollViewer)takingScroll.Parent;
        myScroll.ChangeView(null, myScroll.ScrollableHeight, null, false);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM