none
Placement を Full に設定した Flyout 内で一部の要素をスクロールさせずに配置するには RRS feed

  • 質問

  • 例えば Flyout 内に ListView のような縦に伸びていくコントロールを配置し、そのリストの並び順を操作するためのコントロールを Flyout 内で固定させて表示したい場合についてお聞きします。

    デザインとしてはこういったかたちです。

    基本となるコードは以下になります。

    <Flyout Placement="Full">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
    
            <ComboBox
                Grid.Column="0"
                Header="Filter">
                <ComboBoxItem Content="All"/>
                <ComboBoxItem Content="Male"/>
                <ComboBoxItem Content="Female"/>
            </ComboBox>
            <ComboBox
                Grid.Column="1"
                Header="Sort">
                <ComboBoxItem Content="By height"/>
                <ComboBoxItem Content="By weight"/>
    
            </ComboBox>
    
            <ListView
                Grid.Row="1" Grid.ColumnSpan="2">
                <ListViewItem>
                    <StackPanel>
                        <TextBlock Text="Beth"/>
                        <TextBlock Text="Female, 5.2 feet, 120 pond"/>
                    </StackPanel>
                </ListViewItem>
                <ListViewItem>
                    <StackPanel>
                        <TextBlock Text="Bob"/>
                        <TextBlock Text="Male, 6 feet, 176 pond"/>
                    </StackPanel>
                </ListViewItem>
                ・
                ・
                ・
            </ListView>
        </Grid>
    </Flyout>

    Flyout 直下に配置した Grid は、Flyout の外であれば Grid の二行目のみがスクロールされますが、Flyout 内にある場合には Grid 全体がスクロールされてしまいます。

    まず、Flyout と Grid の ScrollViewer.VerticalScrollMode プロパティを Disabled、ListView の ScrollViewer.VerticalScrollMode プロパティを Enabled に設定しましたが、意図した効果はなく、スクロールの挙動は変わりません。

    また、Placement が Full でない Flyout なら、ListView に MaxHeight などの高さを指定すれば Flyout の高さも増減し、きれいに収めることができるのですが、Full に設定されている場合には Flyout の高さは固定となり、ListView に MaxHeight を指定しても ListView の領域だけが小さくなり、残りが余白として扱われてしまいます。

    FlyoutPresenter スタイルとテンプレートの項目より、FlyoutThemeMaxHeight、FlyoutBorderThemeThickness、FlyoutContentThemePadding の値と、固定表示したい ComboBox の ActualHeight とを計算して ListView の MaxHeight を決めるのは確実ですが、もっと柔軟性のある書き方があるのではと思うのです。

    • 編集済み asato2001 2014年10月27日 9:56
    2014年10月27日 7:50

回答

  • GridのWidthとHeightが親にあるScrollViewerの大きさ以下であれば良いわけで。
    しかし、残念ながらRelativeSoruceにFindAncestorがないので、XAMLでFlyoutPresenter内のScrollViewerをBindingのソースにできません。

    FlyoutPresenterのテンプレートを自分で書くのがベストだと思います。
    リンク先のテンプレートでScrollViewerを抜いてContentPresenterだけにする感じで。

    テンプレートを書き換えたくないならコードで書くしかないのではないでしょか。
    以下適当に書いてみた。

    <Page
        x:Class="App3.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App3"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        <Page.Resources>
    
        </Page.Resources>
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Button Width="100" Height="100" Background="Red">
                <Button.Flyout>
                    <Flyout x:Name="flyout1" Placement="Full"  >
                        <Flyout.FlyoutPresenterStyle>
                            <Style TargetType="FlyoutPresenter" >
                                <!--<Setter Property="Padding" Value="0" />--><!-- 標準だとPaddingがGridのMarginにTemplateBindingされてるみたい-->
                                <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" />
                            </Style>
                        </Flyout.FlyoutPresenterStyle>
                        <Grid  GotFocus="Grid_GotFocus" x:Name="grid1" >
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
    
                                <ComboBox Grid.Column="0" Header="Filter">
                                    <ComboBoxItem Content="All"/>
                                    <ComboBoxItem Content="Male"/>
                                    <ComboBoxItem Content="Female"/>
                                </ComboBox>
                                <ComboBox Grid.Column="1"  Header="Sort">
                                    <ComboBoxItem Content="By height"/>
                                    <ComboBoxItem Content="By weight"/>
    
                                </ComboBox>
    
                                <ListView Grid.Row="1" Grid.ColumnSpan="2" ItemsSource="{Binding}">
                                    <ListView.ItemTemplate>
                                        <DataTemplate>
                                            <StackPanel>
                                                <TextBlock Text="{Binding Path=Name}"/>
                                                <TextBlock Text="{Binding Path=Description}"/>
                                            </StackPanel>
                                        </DataTemplate>
                                    </ListView.ItemTemplate>
                                </ListView>
                            </Grid>
                        </Grid>
                    </Flyout>
                </Button.Flyout>
            </Button>
        </Grid>
    </Page>
    
    using System;
    using System.Collections.Generic;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;
    
    namespace App3
    {
        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
                this.DataContext = Person.CreateDummy();
            }
    
            private void Grid_GotFocus(object sender, RoutedEventArgs e)
            {
                Thickness  margin = new Thickness();
                DependencyObject d;
                d = grid1;//Flyout直下にあるGridから検索開始
                while (d != null)
                {
                    FrameworkElement fe;
                    fe = d as FrameworkElement;
                    if (fe != null)
                    {
                        //余白が設定されているとズレがでるので
                        if (fe.Margin != null && fe.Margin != new Thickness(0))
                        {
                            margin = new Thickness(margin.Left + fe.Margin.Left, margin.Top + fe.Margin.Top, margin.Right + fe.Margin.Right, margin.Bottom + fe.Margin.Bottom);
                            fe.Margin = new Thickness(0);//余白を消してみる
                        }
                    }
    
    
                    if (d is ScrollViewer)
                    {
                        ScrollViewer sc = (ScrollViewer)d;
                        //余計なScrollBarが出ないように。XAMLでFlyoutPresenterのスタイル設定でもいい。
                        sc.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
    
                        //ScrollViewerの大きさを基準にしてGridの大きさを決定する
                        grid1.Width = sc.ActualWidth-margin.Left-margin.Right ;//余白分狭くして適用
                        grid1.Height = sc.ActualHeight - margin.Top - margin.Right;
                        grid1.Margin = margin;//griに余白を適用して
                        break;
                    }
    
                    d = VisualTreeHelper.GetParent(d);
                }
            }
        }
    
        class Person
        {
            public string Name { get; set; }
            public string Description { get; set; }
            public static List<Person> CreateDummy()
            {
                List<Person> persons = new List<Person>();
    
                for (int i = 0; i < 100; i++)
                {
                    Person p = new Person();
                    p.Name = "Name" + i.ToString();
                    p.Description = i.ToString();
                    persons.Add(p);
                }
                return persons;
            }
    
        }
    }
    


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク asato2001 2014年10月28日 1:10
    2014年10月27日 10:32

すべての返信

  • GridのWidthとHeightが親にあるScrollViewerの大きさ以下であれば良いわけで。
    しかし、残念ながらRelativeSoruceにFindAncestorがないので、XAMLでFlyoutPresenter内のScrollViewerをBindingのソースにできません。

    FlyoutPresenterのテンプレートを自分で書くのがベストだと思います。
    リンク先のテンプレートでScrollViewerを抜いてContentPresenterだけにする感じで。

    テンプレートを書き換えたくないならコードで書くしかないのではないでしょか。
    以下適当に書いてみた。

    <Page
        x:Class="App3.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App3"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        <Page.Resources>
    
        </Page.Resources>
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Button Width="100" Height="100" Background="Red">
                <Button.Flyout>
                    <Flyout x:Name="flyout1" Placement="Full"  >
                        <Flyout.FlyoutPresenterStyle>
                            <Style TargetType="FlyoutPresenter" >
                                <!--<Setter Property="Padding" Value="0" />--><!-- 標準だとPaddingがGridのMarginにTemplateBindingされてるみたい-->
                                <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" />
                            </Style>
                        </Flyout.FlyoutPresenterStyle>
                        <Grid  GotFocus="Grid_GotFocus" x:Name="grid1" >
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
    
                                <ComboBox Grid.Column="0" Header="Filter">
                                    <ComboBoxItem Content="All"/>
                                    <ComboBoxItem Content="Male"/>
                                    <ComboBoxItem Content="Female"/>
                                </ComboBox>
                                <ComboBox Grid.Column="1"  Header="Sort">
                                    <ComboBoxItem Content="By height"/>
                                    <ComboBoxItem Content="By weight"/>
    
                                </ComboBox>
    
                                <ListView Grid.Row="1" Grid.ColumnSpan="2" ItemsSource="{Binding}">
                                    <ListView.ItemTemplate>
                                        <DataTemplate>
                                            <StackPanel>
                                                <TextBlock Text="{Binding Path=Name}"/>
                                                <TextBlock Text="{Binding Path=Description}"/>
                                            </StackPanel>
                                        </DataTemplate>
                                    </ListView.ItemTemplate>
                                </ListView>
                            </Grid>
                        </Grid>
                    </Flyout>
                </Button.Flyout>
            </Button>
        </Grid>
    </Page>
    
    using System;
    using System.Collections.Generic;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;
    
    namespace App3
    {
        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
                this.DataContext = Person.CreateDummy();
            }
    
            private void Grid_GotFocus(object sender, RoutedEventArgs e)
            {
                Thickness  margin = new Thickness();
                DependencyObject d;
                d = grid1;//Flyout直下にあるGridから検索開始
                while (d != null)
                {
                    FrameworkElement fe;
                    fe = d as FrameworkElement;
                    if (fe != null)
                    {
                        //余白が設定されているとズレがでるので
                        if (fe.Margin != null && fe.Margin != new Thickness(0))
                        {
                            margin = new Thickness(margin.Left + fe.Margin.Left, margin.Top + fe.Margin.Top, margin.Right + fe.Margin.Right, margin.Bottom + fe.Margin.Bottom);
                            fe.Margin = new Thickness(0);//余白を消してみる
                        }
                    }
    
    
                    if (d is ScrollViewer)
                    {
                        ScrollViewer sc = (ScrollViewer)d;
                        //余計なScrollBarが出ないように。XAMLでFlyoutPresenterのスタイル設定でもいい。
                        sc.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
    
                        //ScrollViewerの大きさを基準にしてGridの大きさを決定する
                        grid1.Width = sc.ActualWidth-margin.Left-margin.Right ;//余白分狭くして適用
                        grid1.Height = sc.ActualHeight - margin.Top - margin.Right;
                        grid1.Margin = margin;//griに余白を適用して
                        break;
                    }
    
                    d = VisualTreeHelper.GetParent(d);
                }
            }
        }
    
        class Person
        {
            public string Name { get; set; }
            public string Description { get; set; }
            public static List<Person> CreateDummy()
            {
                List<Person> persons = new List<Person>();
    
                for (int i = 0; i < 100; i++)
                {
                    Person p = new Person();
                    p.Name = "Name" + i.ToString();
                    p.Description = i.ToString();
                    persons.Add(p);
                }
                return persons;
            }
    
        }
    }
    


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク asato2001 2014年10月28日 1:10
    2014年10月27日 10:32
  • なるほど、FlyoutPresenter 内の ScrollViewer を削除しておけば、スクロール バーが ListView と重複することがなくなるのですね。以下のテンプレートを書き換えるかたちで追加したコードで、目的の動作ができるようになりました。ありがとうございました。

    <Flyout Placement="Full">
        <Flyout.FlyoutPresenterStyle>
            <Style TargetType="FlyoutPresenter">
                <Setter Property="Padding" Value="20,17,20,0"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="FlyoutPresenter">
                            <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">
                                <ContentPresenter Content="{TemplateBinding Content}"
                                    ContentTemplate="{TemplateBinding ContentTemplate}"
                                    ContentTransitions="{TemplateBinding ContentTransitions}"
                                    Margin="{TemplateBinding Padding}"
                                    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Flyout.FlyoutPresenterStyle>
        <Grid>
        ・
        ・
        ・
        </Grid>
    </Flyout>
    2014年10月28日 1:10