none
ItemsPanelTemplateに適用するカスタムパネルで、任意の要素でスクロールバー表示を行う方法 RRS feed

  • 質問

  • WPFのItemsControlのItemsPanelTemplateで使用する独自のカスタムパネル(Panel)を作成していますが、複数の任意の要素が、合わせて一定の高さを超える場合にはその範囲内でスクロールバー表示させたいと思っています。

    そのためにはどのように作成するとよいでしょうか?

    例:ItemsControlが5個の要素(Item1-Item5)を持っていた場合に、2個目と3個目要素が合わせて一定の高さを超える場合にはその範囲でスクロールバーを表示させる。


    • 編集済み yj0529 2018年4月10日 9:57
    2018年4月10日 5:46

回答

  • 方法1 : ItemsPanelは触らずにグループ化をつかってみる

    <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:app="clr-namespace:WpfApplication1" Title="MainWindow" Height="350" Width="525">
    
        <ItemsControl app:ItemsControlTool.GroupName="GroupKey" 
                      app:ItemsControlTool.ItemsSource="{Binding}">
    
            <ItemsControl.GroupStyle>
                <GroupStyle >
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate />
                    </GroupStyle.HeaderTemplate>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Template" >
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type GroupItem}">
                                        <ScrollViewer MaxHeight="{Binding Path=Name.MaxLength,FallbackValue=1e100}" 
                                                          VerticalScrollBarVisibility="Auto"
                                                          HorizontalScrollBarVisibility="Disabled">
                                            <StackPanel>
                                                <ContentPresenter x:Name="PART_Header"/>
                                                <ItemsPresenter x:Name="ItemsPresenter" Margin="5,0,0,0"/>
                                            </StackPanel>
                                        </ScrollViewer>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
            </ItemsControl.GroupStyle>
    
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="{x:Type ContentPresenter}">
                    <Setter Property="Height" Value="{Binding Path=Length}" />
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border VerticalAlignment="Stretch" BorderBrush="Black" BorderThickness="1" Margin="2"
                                Background="{Binding Path=Brush}">
                        <StackPanel>
                            <Slider Minimum="30" Maximum="200" Value="{Binding Path=Length}"/>
                            <TextBlock>
                                        <Run Text="{Binding Path=Name,Mode=OneWay}"/>
                                        <Run Text="="/>
                                        <Run Text="{Binding Path=Length,Mode=OneWay}"/>
                            </TextBlock>
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Window>

    namespace WpfApplication1
    {
        using System;
        using System.Collections.Generic;
        using System.Windows;
        using System.Windows.Controls;
        using System.Windows.Data;
        using System.Windows.Documents;
        using System.Windows.Media;
    
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                this.DataContext = Item.CreateTestItems();
            }
        }
    
        class ItemsControlTool
        {
            public static string GetGroupName(DependencyObject obj) { return (string)obj.GetValue(GroupNameProperty); }
            public static void SetGroupName(DependencyObject obj, string value) { obj.SetValue(GroupNameProperty, value); }
            public static readonly DependencyProperty GroupNameProperty = DependencyProperty.RegisterAttached("GroupName", typeof(string), typeof(ItemsControlTool), new UIPropertyMetadata(default(string), OnPropertyChanged));
    
            public static System.Collections.IEnumerable GetItemsSource(ItemsControl obj) { return (System.Collections.IEnumerable)obj.GetValue(ItemsSourceProperty); }
            public static void SetItemsSource(ItemsControl obj, System.Collections.IEnumerable value) { obj.SetValue(ItemsSourceProperty, value); }
            public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.RegisterAttached("ItemsSource", typeof(System.Collections.IEnumerable), typeof(ItemsControlTool), new UIPropertyMetadata(default(System.Collections.IEnumerable), OnPropertyChanged));
    
            private static void OnPropertyChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs e)
            {
                ItemsControl target = dpo as ItemsControl;
                if (target != null)
                {
    
    
                    System.Collections.IEnumerable newSource = GetItemsSource(target);
                    string groupName = GetGroupName(target);
    
    
                    if (newSource != null && !string.IsNullOrWhiteSpace(groupName))
                    {
                        //与えられたItemsSourceをグループ化する
                        CollectionViewSource cvs = new CollectionViewSource();
                        cvs.Source = newSource;
                        cvs.GroupDescriptions.Add(new System.Windows.Data.PropertyGroupDescription(groupName));
                        target.ItemsSource = cvs.View;
                    }
                    else
                    {
                        target.ClearValue(ItemsControl.ItemsSourceProperty);
                    }
                }
            }
    
        }
    
        class ModelBase : System.ComponentModel.INotifyPropertyChanged
        {
            public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged(string name)
            {
                var pc = PropertyChanged;
                if (pc != null) { pc(this, new System.ComponentModel.PropertyChangedEventArgs(name)); }
            }
        }
    
        class Item : ModelBase
        {
            public static List<Item> CreateTestItems()
            {
                List<Item> items = new List<Item>();
    
                items.Add(new Item() { Name = "Item1", Length = 50, GroupKey = new ScrollGroup(), Brush = Brushes.Red });
                items.Add(new Item() { Name = "Item2", Length = 50, GroupKey = new ScrollGroup(), Brush = Brushes.Yellow });
                items.Add(new Item() { Name = "Item3", Length = 50, GroupKey = new ScrollGroup(), Brush = Brushes.LightSkyBlue });
                items.Add(new Item() { Name = "Item4", Length = 50, GroupKey = new ScrollGroup(), Brush = Brushes.LightGreen });
                items.Add(new Item() { Name = "Item5", Length = 50, GroupKey = new ScrollGroup(), Brush = Brushes.Pink });
    
    
                items[1].GroupKey = items[2].GroupKey;
                items[1].GroupKey.MaxLength = 100;
    
                return items;
            }
    
    
            public ScrollGroup GroupKey { get; set; }
    
            public string Name { get; set; }
    
            public double Length
            {
                get { return _Length; }
                set { if (_Length != value) { _Length = value; OnPropertyChanged("Length"); } }
            }
            private double _Length;
    
            public Brush Brush { get; set; }
        }
    
        class ScrollGroup
        {
            public ScrollGroup()
            {
                MaxLength = double.MaxValue;
            }
            public double MaxLength { get; set; }
        }
    }

    方法2 : StackPanelの内部に疑似スクロール領域を作る面倒な処理をしてみる

    <Window x:Class="WpfApplication2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:app="clr-namespace:WpfApplication2" Title="MainWindow" Height="350" Width="525">
    
    
        <ItemsControl ItemsSource="{Binding}" VerticalAlignment="Top">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <app:Panel ViewWindowSize="150" IndexMin="1" IndexMax="2"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="{x:Type ContentPresenter}">
                    <Setter Property="Height" Value="{Binding Path=Length}" />
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border VerticalAlignment="Stretch" BorderBrush="Black" BorderThickness="1" Margin="2"
                                Background="{Binding Path=Brush}">
                        <StackPanel>
                            <Slider Minimum="30" Maximum="200" Value="{Binding Path=Length}"/>
                            <TextBlock>
                                        <Run Text="{Binding Path=Name,Mode=OneWay}"/>
                                        <Run Text="="/>
                                        <Run Text="{Binding Path=Length,Mode=OneWay}"/>
                            </TextBlock>
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Window>
    namespace WpfApplication2
    {
        using System;
        using System.Collections.Generic;
        using System.Windows;
        using System.Windows.Controls;
        using System.Windows.Documents;
        using System.Windows.Media;
    
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                this.DataContext = Item.CreateTestItems();
            }
        }
    
        class scrollAdorner : Adorner
        {
            public scrollAdorner(UIElement adornedElement)
                : base(adornedElement)
            {
                _canvas = new Canvas();
                _canvas.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
                _canvas.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                _canvas.Width = 0;
                _canvas.Height = 0;
                this.AddVisualChild(_canvas);
    
            }
            public Canvas Canvas { get { return _canvas; } }
            private Canvas _canvas;
    
            protected override int VisualChildrenCount
            {
                get
                {
                    return 1;
                }
            }
            protected override Visual GetVisualChild(int index)
            {
                return _canvas;
            }
            protected override Size MeasureOverride(Size constraint)
            {
                _canvas.Width = constraint.Width;
                return base.MeasureOverride(constraint);
            }
            protected override Size ArrangeOverride(Size finalSize)
            {
                Rect rect = new Rect(0, 0, finalSize.Width, finalSize.Height);
                _canvas.Arrange(rect);
                return finalSize;
            }
        }
    
        class Panel : StackPanel
        {
            private System.Windows.Controls.Primitives.ScrollBar _scrollBar = new System.Windows.Controls.Primitives.ScrollBar();
    
            public Panel()
            {
                this._scrollBar.ValueChanged += _scrollBar_ValueChanged;
                this.Loaded += Panel_Loaded;
            }
    
            void Panel_Loaded(object sender, RoutedEventArgs e)
            {
                var scrollAdorner = new scrollAdorner(this);
                scrollAdorner.Canvas.Children.Add(this._scrollBar);
    
                var adornerLayer = AdornerLayer.GetAdornerLayer(this);
                adornerLayer.Add(scrollAdorner);
            }
    
    
    
            private void _scrollBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
            {
                this.InvalidateArrange();
            }
    
            /// <summary>スクロールバーを出す高さ</summary>
            public double ViewWindowSize
            {
                get { return (double)GetValue(ViewWindowSizeProperty); }
                set { SetValue(ViewWindowSizeProperty, value); }
            }
    
            public static readonly DependencyProperty ViewWindowSizeProperty =
                DependencyProperty.Register("ViewWindowSize", typeof(double), typeof(Panel)
                , new FrameworkPropertyMetadata
                    (default(double), FrameworkPropertyMetadataOptions.AffectsParentMeasure));
    
    
            public int IndexMin
            {
                get { return (int)GetValue(IndexMinProperty); }
                set { SetValue(IndexMinProperty, value); }
            }
    
            public static readonly DependencyProperty IndexMinProperty =
                DependencyProperty.Register("IndexMin", typeof(int), typeof(Panel)
                , new FrameworkPropertyMetadata
                    (default(int), FrameworkPropertyMetadataOptions.AffectsParentMeasure));
    
    
            public int IndexMax
            {
                get { return (int)GetValue(IndexMaxProperty); }
                set { SetValue(IndexMaxProperty, value); }
            }
    
            public static readonly DependencyProperty IndexMaxProperty =
                DependencyProperty.Register("IndexMax", typeof(int), typeof(Panel)
                , new FrameworkPropertyMetadata
                     (default(int), FrameworkPropertyMetadataOptions.AffectsParentMeasure));
    
    
    
            protected override Size MeasureOverride(Size constraint)
            {
    
                var retval = base.MeasureOverride(constraint);
                if (IndexMin < IndexMax)
                {
                    int count = this.VisualChildrenCount;
                    double height = 0;
                    double heightInner = 0;
                    for (int index = 0; index < count; index++)
                    {
                        UIElement element = this.GetVisualChild(index) as UIElement;
                        if (IndexMin <= index && index < IndexMax)
                        {
                            heightInner += element.DesiredSize.Height;
                        }
                        else if (index == IndexMax)
                        {
                            heightInner += element.DesiredSize.Height;
    
                            if (heightInner >= ViewWindowSize)
                            {
                                height += ViewWindowSize;
                            }
                            else
                            {
                                height += heightInner;
                            }
                        }
                        else
                        {
                            height += element.DesiredSize.Height;
                        }
                    }
                    retval.Height = height;
                }
                return retval;
            }
    
            protected override Size ArrangeOverride(Size arrangeSize)
            {
                double top = 0;
                double y = 0;
                _scrollBar.Height = ViewWindowSize;
                double scrollMax = 0;
                int count = VisualChildrenCount;
                for (int index = 0; index < count; index++)
                {
                    UIElement element = this.GetVisualChild(index) as UIElement;
    
                    if (IndexMin <= index && index < IndexMax)
                    {
                        top = y;
                        scrollMax += element.DesiredSize.Height;
                    }
                    else if (index == IndexMax)
                    {
                        scrollMax += element.DesiredSize.Height;
    
                        if (scrollMax >= ViewWindowSize)
                        {
                            _scrollBar.Visibility = System.Windows.Visibility.Visible;
                            y += ViewWindowSize;
                        }
                        else
                        {
                            _scrollBar.Visibility = System.Windows.Visibility.Collapsed;
                            _scrollBar.Value = 0;
                            y += scrollMax;
                        }
                    }
                    else
                    {
                        var r = new Rect(0, y, arrangeSize.Width, element.DesiredSize.Height);
                        element.Arrange(r);
                        y += element.DesiredSize.Height;
                        element.RenderTransform = null;
                    }
                }
    
                _scrollBar.Maximum = System.Math.Max(0, scrollMax - ViewWindowSize);
                _scrollBar.ViewportSize = ViewWindowSize;
                if (_scrollBar.Visibility == System.Windows.Visibility.Visible)
                {
                    //スクロールバーの表示位置を調整
                    Canvas.SetTop(_scrollBar, top);
                    Canvas.SetRight(_scrollBar, 0);
                }
    
    
                double offset = _scrollBar.Value;
    
                TranslateTransform tt = new TranslateTransform();
                tt.X = 0;
                tt.Y = -offset;
    
                Rect viewWindow = new Rect(0, offset, arrangeSize.Width, ViewWindowSize);
                y = top;
    
                for (int index = 0; index < VisualChildrenCount; index++)
                {
                    UIElement element = this.GetVisualChild(index) as UIElement;
                    if (IndexMin <= index && index <= IndexMax)
                    {
                        Rect clipRect = new Rect(0, 0, arrangeSize.Width, element.DesiredSize.Height);
                        clipRect.Intersect(viewWindow);
                        if (clipRect.Height > 0)
                        {
                            //表示される部分があるなら、
                            //RenderTransformで位置をずらして、
                            //Clipで描画される領域を制限して、
                            //疑似スクロール状態を作って配置
                            element.RenderTransform = tt;
                            element.Clip = new RectangleGeometry() { Rect = clipRect };
                            element.Arrange(new Rect(0, y, arrangeSize.Width, element.DesiredSize.Height));
                        }
    
                        y += element.DesiredSize.Height;
                        viewWindow.Offset(0, -element.DesiredSize.Height);
                    }
                }
    
                return arrangeSize;
    
            }
        }
    
        class ModelBase : System.ComponentModel.INotifyPropertyChanged
        {
            public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged(string name)
            {
                var pc = PropertyChanged;
                if (pc != null) { pc(this, new System.ComponentModel.PropertyChangedEventArgs(name)); }
            }
        }
    
        class Item : ModelBase
        {
            public static List<Item> CreateTestItems()
            {
    
                List<Item> items = new List<Item>();
                items.Add(new Item() { Name = "Item1", Length = 50, Brush = Brushes.Red });
                items.Add(new Item() { Name = "Item2", Length = 50, Brush = Brushes.Yellow });
                items.Add(new Item() { Name = "Item3", Length = 50, Brush = Brushes.LightSkyBlue });
                items.Add(new Item() { Name = "Item4", Length = 50, Brush = Brushes.LightGreen });
                items.Add(new Item() { Name = "Item5", Length = 50, Brush = Brushes.Pink });
                return items;
            }
    
    
            public string Name { get; set; }
    
            public double Length
            {
                get { return _Length; }
                set { if (_Length != value) { _Length = value; OnPropertyChanged("Length"); } }
            }
            private double _Length;
    
            public Brush Brush { get; set; }
        }
    }

    #最初から分割して複数のItemsControlに振り分けた方が楽だと思う


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

    • 回答としてマーク yj0529 2018年4月12日 1:40
    2018年4月10日 12:32

すべての返信

  • 方法1 : ItemsPanelは触らずにグループ化をつかってみる

    <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:app="clr-namespace:WpfApplication1" Title="MainWindow" Height="350" Width="525">
    
        <ItemsControl app:ItemsControlTool.GroupName="GroupKey" 
                      app:ItemsControlTool.ItemsSource="{Binding}">
    
            <ItemsControl.GroupStyle>
                <GroupStyle >
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate />
                    </GroupStyle.HeaderTemplate>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Template" >
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type GroupItem}">
                                        <ScrollViewer MaxHeight="{Binding Path=Name.MaxLength,FallbackValue=1e100}" 
                                                          VerticalScrollBarVisibility="Auto"
                                                          HorizontalScrollBarVisibility="Disabled">
                                            <StackPanel>
                                                <ContentPresenter x:Name="PART_Header"/>
                                                <ItemsPresenter x:Name="ItemsPresenter" Margin="5,0,0,0"/>
                                            </StackPanel>
                                        </ScrollViewer>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
            </ItemsControl.GroupStyle>
    
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="{x:Type ContentPresenter}">
                    <Setter Property="Height" Value="{Binding Path=Length}" />
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border VerticalAlignment="Stretch" BorderBrush="Black" BorderThickness="1" Margin="2"
                                Background="{Binding Path=Brush}">
                        <StackPanel>
                            <Slider Minimum="30" Maximum="200" Value="{Binding Path=Length}"/>
                            <TextBlock>
                                        <Run Text="{Binding Path=Name,Mode=OneWay}"/>
                                        <Run Text="="/>
                                        <Run Text="{Binding Path=Length,Mode=OneWay}"/>
                            </TextBlock>
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Window>

    namespace WpfApplication1
    {
        using System;
        using System.Collections.Generic;
        using System.Windows;
        using System.Windows.Controls;
        using System.Windows.Data;
        using System.Windows.Documents;
        using System.Windows.Media;
    
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                this.DataContext = Item.CreateTestItems();
            }
        }
    
        class ItemsControlTool
        {
            public static string GetGroupName(DependencyObject obj) { return (string)obj.GetValue(GroupNameProperty); }
            public static void SetGroupName(DependencyObject obj, string value) { obj.SetValue(GroupNameProperty, value); }
            public static readonly DependencyProperty GroupNameProperty = DependencyProperty.RegisterAttached("GroupName", typeof(string), typeof(ItemsControlTool), new UIPropertyMetadata(default(string), OnPropertyChanged));
    
            public static System.Collections.IEnumerable GetItemsSource(ItemsControl obj) { return (System.Collections.IEnumerable)obj.GetValue(ItemsSourceProperty); }
            public static void SetItemsSource(ItemsControl obj, System.Collections.IEnumerable value) { obj.SetValue(ItemsSourceProperty, value); }
            public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.RegisterAttached("ItemsSource", typeof(System.Collections.IEnumerable), typeof(ItemsControlTool), new UIPropertyMetadata(default(System.Collections.IEnumerable), OnPropertyChanged));
    
            private static void OnPropertyChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs e)
            {
                ItemsControl target = dpo as ItemsControl;
                if (target != null)
                {
    
    
                    System.Collections.IEnumerable newSource = GetItemsSource(target);
                    string groupName = GetGroupName(target);
    
    
                    if (newSource != null && !string.IsNullOrWhiteSpace(groupName))
                    {
                        //与えられたItemsSourceをグループ化する
                        CollectionViewSource cvs = new CollectionViewSource();
                        cvs.Source = newSource;
                        cvs.GroupDescriptions.Add(new System.Windows.Data.PropertyGroupDescription(groupName));
                        target.ItemsSource = cvs.View;
                    }
                    else
                    {
                        target.ClearValue(ItemsControl.ItemsSourceProperty);
                    }
                }
            }
    
        }
    
        class ModelBase : System.ComponentModel.INotifyPropertyChanged
        {
            public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged(string name)
            {
                var pc = PropertyChanged;
                if (pc != null) { pc(this, new System.ComponentModel.PropertyChangedEventArgs(name)); }
            }
        }
    
        class Item : ModelBase
        {
            public static List<Item> CreateTestItems()
            {
                List<Item> items = new List<Item>();
    
                items.Add(new Item() { Name = "Item1", Length = 50, GroupKey = new ScrollGroup(), Brush = Brushes.Red });
                items.Add(new Item() { Name = "Item2", Length = 50, GroupKey = new ScrollGroup(), Brush = Brushes.Yellow });
                items.Add(new Item() { Name = "Item3", Length = 50, GroupKey = new ScrollGroup(), Brush = Brushes.LightSkyBlue });
                items.Add(new Item() { Name = "Item4", Length = 50, GroupKey = new ScrollGroup(), Brush = Brushes.LightGreen });
                items.Add(new Item() { Name = "Item5", Length = 50, GroupKey = new ScrollGroup(), Brush = Brushes.Pink });
    
    
                items[1].GroupKey = items[2].GroupKey;
                items[1].GroupKey.MaxLength = 100;
    
                return items;
            }
    
    
            public ScrollGroup GroupKey { get; set; }
    
            public string Name { get; set; }
    
            public double Length
            {
                get { return _Length; }
                set { if (_Length != value) { _Length = value; OnPropertyChanged("Length"); } }
            }
            private double _Length;
    
            public Brush Brush { get; set; }
        }
    
        class ScrollGroup
        {
            public ScrollGroup()
            {
                MaxLength = double.MaxValue;
            }
            public double MaxLength { get; set; }
        }
    }

    方法2 : StackPanelの内部に疑似スクロール領域を作る面倒な処理をしてみる

    <Window x:Class="WpfApplication2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:app="clr-namespace:WpfApplication2" Title="MainWindow" Height="350" Width="525">
    
    
        <ItemsControl ItemsSource="{Binding}" VerticalAlignment="Top">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <app:Panel ViewWindowSize="150" IndexMin="1" IndexMax="2"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="{x:Type ContentPresenter}">
                    <Setter Property="Height" Value="{Binding Path=Length}" />
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border VerticalAlignment="Stretch" BorderBrush="Black" BorderThickness="1" Margin="2"
                                Background="{Binding Path=Brush}">
                        <StackPanel>
                            <Slider Minimum="30" Maximum="200" Value="{Binding Path=Length}"/>
                            <TextBlock>
                                        <Run Text="{Binding Path=Name,Mode=OneWay}"/>
                                        <Run Text="="/>
                                        <Run Text="{Binding Path=Length,Mode=OneWay}"/>
                            </TextBlock>
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Window>
    namespace WpfApplication2
    {
        using System;
        using System.Collections.Generic;
        using System.Windows;
        using System.Windows.Controls;
        using System.Windows.Documents;
        using System.Windows.Media;
    
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                this.DataContext = Item.CreateTestItems();
            }
        }
    
        class scrollAdorner : Adorner
        {
            public scrollAdorner(UIElement adornedElement)
                : base(adornedElement)
            {
                _canvas = new Canvas();
                _canvas.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
                _canvas.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                _canvas.Width = 0;
                _canvas.Height = 0;
                this.AddVisualChild(_canvas);
    
            }
            public Canvas Canvas { get { return _canvas; } }
            private Canvas _canvas;
    
            protected override int VisualChildrenCount
            {
                get
                {
                    return 1;
                }
            }
            protected override Visual GetVisualChild(int index)
            {
                return _canvas;
            }
            protected override Size MeasureOverride(Size constraint)
            {
                _canvas.Width = constraint.Width;
                return base.MeasureOverride(constraint);
            }
            protected override Size ArrangeOverride(Size finalSize)
            {
                Rect rect = new Rect(0, 0, finalSize.Width, finalSize.Height);
                _canvas.Arrange(rect);
                return finalSize;
            }
        }
    
        class Panel : StackPanel
        {
            private System.Windows.Controls.Primitives.ScrollBar _scrollBar = new System.Windows.Controls.Primitives.ScrollBar();
    
            public Panel()
            {
                this._scrollBar.ValueChanged += _scrollBar_ValueChanged;
                this.Loaded += Panel_Loaded;
            }
    
            void Panel_Loaded(object sender, RoutedEventArgs e)
            {
                var scrollAdorner = new scrollAdorner(this);
                scrollAdorner.Canvas.Children.Add(this._scrollBar);
    
                var adornerLayer = AdornerLayer.GetAdornerLayer(this);
                adornerLayer.Add(scrollAdorner);
            }
    
    
    
            private void _scrollBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
            {
                this.InvalidateArrange();
            }
    
            /// <summary>スクロールバーを出す高さ</summary>
            public double ViewWindowSize
            {
                get { return (double)GetValue(ViewWindowSizeProperty); }
                set { SetValue(ViewWindowSizeProperty, value); }
            }
    
            public static readonly DependencyProperty ViewWindowSizeProperty =
                DependencyProperty.Register("ViewWindowSize", typeof(double), typeof(Panel)
                , new FrameworkPropertyMetadata
                    (default(double), FrameworkPropertyMetadataOptions.AffectsParentMeasure));
    
    
            public int IndexMin
            {
                get { return (int)GetValue(IndexMinProperty); }
                set { SetValue(IndexMinProperty, value); }
            }
    
            public static readonly DependencyProperty IndexMinProperty =
                DependencyProperty.Register("IndexMin", typeof(int), typeof(Panel)
                , new FrameworkPropertyMetadata
                    (default(int), FrameworkPropertyMetadataOptions.AffectsParentMeasure));
    
    
            public int IndexMax
            {
                get { return (int)GetValue(IndexMaxProperty); }
                set { SetValue(IndexMaxProperty, value); }
            }
    
            public static readonly DependencyProperty IndexMaxProperty =
                DependencyProperty.Register("IndexMax", typeof(int), typeof(Panel)
                , new FrameworkPropertyMetadata
                     (default(int), FrameworkPropertyMetadataOptions.AffectsParentMeasure));
    
    
    
            protected override Size MeasureOverride(Size constraint)
            {
    
                var retval = base.MeasureOverride(constraint);
                if (IndexMin < IndexMax)
                {
                    int count = this.VisualChildrenCount;
                    double height = 0;
                    double heightInner = 0;
                    for (int index = 0; index < count; index++)
                    {
                        UIElement element = this.GetVisualChild(index) as UIElement;
                        if (IndexMin <= index && index < IndexMax)
                        {
                            heightInner += element.DesiredSize.Height;
                        }
                        else if (index == IndexMax)
                        {
                            heightInner += element.DesiredSize.Height;
    
                            if (heightInner >= ViewWindowSize)
                            {
                                height += ViewWindowSize;
                            }
                            else
                            {
                                height += heightInner;
                            }
                        }
                        else
                        {
                            height += element.DesiredSize.Height;
                        }
                    }
                    retval.Height = height;
                }
                return retval;
            }
    
            protected override Size ArrangeOverride(Size arrangeSize)
            {
                double top = 0;
                double y = 0;
                _scrollBar.Height = ViewWindowSize;
                double scrollMax = 0;
                int count = VisualChildrenCount;
                for (int index = 0; index < count; index++)
                {
                    UIElement element = this.GetVisualChild(index) as UIElement;
    
                    if (IndexMin <= index && index < IndexMax)
                    {
                        top = y;
                        scrollMax += element.DesiredSize.Height;
                    }
                    else if (index == IndexMax)
                    {
                        scrollMax += element.DesiredSize.Height;
    
                        if (scrollMax >= ViewWindowSize)
                        {
                            _scrollBar.Visibility = System.Windows.Visibility.Visible;
                            y += ViewWindowSize;
                        }
                        else
                        {
                            _scrollBar.Visibility = System.Windows.Visibility.Collapsed;
                            _scrollBar.Value = 0;
                            y += scrollMax;
                        }
                    }
                    else
                    {
                        var r = new Rect(0, y, arrangeSize.Width, element.DesiredSize.Height);
                        element.Arrange(r);
                        y += element.DesiredSize.Height;
                        element.RenderTransform = null;
                    }
                }
    
                _scrollBar.Maximum = System.Math.Max(0, scrollMax - ViewWindowSize);
                _scrollBar.ViewportSize = ViewWindowSize;
                if (_scrollBar.Visibility == System.Windows.Visibility.Visible)
                {
                    //スクロールバーの表示位置を調整
                    Canvas.SetTop(_scrollBar, top);
                    Canvas.SetRight(_scrollBar, 0);
                }
    
    
                double offset = _scrollBar.Value;
    
                TranslateTransform tt = new TranslateTransform();
                tt.X = 0;
                tt.Y = -offset;
    
                Rect viewWindow = new Rect(0, offset, arrangeSize.Width, ViewWindowSize);
                y = top;
    
                for (int index = 0; index < VisualChildrenCount; index++)
                {
                    UIElement element = this.GetVisualChild(index) as UIElement;
                    if (IndexMin <= index && index <= IndexMax)
                    {
                        Rect clipRect = new Rect(0, 0, arrangeSize.Width, element.DesiredSize.Height);
                        clipRect.Intersect(viewWindow);
                        if (clipRect.Height > 0)
                        {
                            //表示される部分があるなら、
                            //RenderTransformで位置をずらして、
                            //Clipで描画される領域を制限して、
                            //疑似スクロール状態を作って配置
                            element.RenderTransform = tt;
                            element.Clip = new RectangleGeometry() { Rect = clipRect };
                            element.Arrange(new Rect(0, y, arrangeSize.Width, element.DesiredSize.Height));
                        }
    
                        y += element.DesiredSize.Height;
                        viewWindow.Offset(0, -element.DesiredSize.Height);
                    }
                }
    
                return arrangeSize;
    
            }
        }
    
        class ModelBase : System.ComponentModel.INotifyPropertyChanged
        {
            public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged(string name)
            {
                var pc = PropertyChanged;
                if (pc != null) { pc(this, new System.ComponentModel.PropertyChangedEventArgs(name)); }
            }
        }
    
        class Item : ModelBase
        {
            public static List<Item> CreateTestItems()
            {
    
                List<Item> items = new List<Item>();
                items.Add(new Item() { Name = "Item1", Length = 50, Brush = Brushes.Red });
                items.Add(new Item() { Name = "Item2", Length = 50, Brush = Brushes.Yellow });
                items.Add(new Item() { Name = "Item3", Length = 50, Brush = Brushes.LightSkyBlue });
                items.Add(new Item() { Name = "Item4", Length = 50, Brush = Brushes.LightGreen });
                items.Add(new Item() { Name = "Item5", Length = 50, Brush = Brushes.Pink });
                return items;
            }
    
    
            public string Name { get; set; }
    
            public double Length
            {
                get { return _Length; }
                set { if (_Length != value) { _Length = value; OnPropertyChanged("Length"); } }
            }
            private double _Length;
    
            public Brush Brush { get; set; }
        }
    }

    #最初から分割して複数のItemsControlに振り分けた方が楽だと思う


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

    • 回答としてマーク yj0529 2018年4月12日 1:40
    2018年4月10日 12:32
  • gekka様

    ご返信ありがとうございます。

    教えていただいた内容がとても参考になります!本当にありがとうございました。

    2018年4月11日 0:39
  • yjm0529 さん、こんにちは。フォーラム オペレーターの立花です。
    MSDN フォーラムにご投稿下しましてありがとうございます。

    フォーラム オペレーターからのお願いです。

    参考となる返信がございましたら、その返信に [回答としてマーク] を
    設定いただけますと、後から参照した方がすぐに情報を得られたり、
    回答いただいた方のモチベーションの向上にもつながります。

    お手数ではございますが、ご設定にご協力をお願いいたしします。


    参考になった投稿には回答としてマークの設定にご協力ください
    MSDN/TechNet Community Support 立花楓

    2018年4月11日 1:10
    モデレータ