InputPanel for WPF
InputPanel と FlexGrid の統合

FlexGrid の場合は、空のテンプレートとセルファクトリオブジェクトを作成して行の詳細を表示する必要があるため、InputPanel の統合は少し複雑です。

次の図に、FlexGrid と統合された InputPanel を示します。

InputPanel を FlexGrid と統合するには、次の手順を実行します。
  1. アプリケーションの設定
  2. データソースの作成
  3. InputPanel を追加する空のテンプレートの作成
  4. InputPanel とテンプレートとの統合

先頭に戻る

アプリケーションの設定

  1. WPF アプリケーションを作成し、デザイナに FlexGrid コントロールを追加します。
  2. XAML ビューで列幅と最小の行の高さを設定します。
    XAML
    コードのコピー
    <Grid>
        <c1:C1FlexGrid x:Name="FlexGrid" MinRowHeight="1">
            <c1:C1FlexGrid.Columns>
                <c1:Column Width="20" IsReadOnly="True"/>
            </c1:C1FlexGrid.Columns>             
        </c1:C1FlexGrid>
    </Grid>
    
  3. 新しいフォルダ Resources を追加し、統合された InputPanel の展開と折りたたみに使用する 2 つの画像をそこに追加します。

先頭に戻る

データソースの作成

  1. コードビューに切り替え、InputPanel にレコードを追加するための Customer クラスを作成し、Occupation フィールドの値を受け入れる列挙を作成します。
    Public Class Customer
        Public Property ID() As String
            Get
                Return m_ID
            End Get
            Set(value As String)
                m_ID = Value
            End Set
        End Property
        Private m_ID As String
        Public Property 国() As String
            Get
                Return m_Country
            End Get
            Set(value As String)
                m_Country = Value
            End Set
        End Property
        Private m_Country As String
    
        Public Property 名前() As String
            Get
                Return m_Name
            End Get
            Set(value As String)
                m_Name = Value
            End Set
        End Property
        Private m_Name As String
    
    
        Public Property 年齢() As Integer
            Get
                Return m_Age
            End Get
            Set(value As Integer)
                m_Age = Value
            End Set
        End Property
        Private m_Age As Integer
        Public Property 重量() As Double
            Get
                Return m_Weight
            End Get
            Set(value As Double)
                m_Weight = Value
            End Set
        End Property
        Private m_Weight As Double
        Public Property 職業() As Occupation
            Get
                Return m_Occupation
            End Get
            Set(value As Occupation)
                m_Occupation = Value
            End Set
        End Property
        Private m_Occupation As Occupation
        Public Property 電話番号() As String
            Get
                Return m_Phone
            End Get
            Set(value As String)
                m_Phone = Value
            End Set
        End Property
        Private m_Phone As String
        Public Property 給料() As Integer
            Get
                Return m_Salary
            End Get
            Set(value As Integer)
                m_Salary = Value
            End Set
        End Property
        Private m_Salary As Integer
    
        Public Sub New(id As String, country As String, _
                       name As String, age As Integer, weight As Double, _
                       occupation As Occupation, _
            phone As String, salary As Integer)
            Me.ID = id
            Me.国 = country
            Me.名前 = name
            Me.年齢 = age
            Me.重量 = weight
            Me.職業 = occupation
            Me.電話番号 = phone
            Me.給料 = salary
        End Sub
    End Class
    
    Public Enum Occupation
            医者,
            芸術家,
            教育者,
            エンジニア,
            重役,
            その他
    End Enum
    
    public class Customer
    {
       public string ID { get; set; }
        public string 国 { get; set; }     
        public string 名前 { get; set; }
        public string 電話番号 { get; set; }
        public int 給料 { get; set; }
        public int 年齢 { get; set; }
        public double 重量 { get; set; }
        public Occupation 職業 { get; set; }
    
        public Customer(string id, string country, string name, 
            int age, double weight, Occupation occupation, string phone, int salary)
        {
            this.ID = id;
            this.国 = country;
            this.名前 = name;
            this.年齢 = age;
            this.重量 = weight;
            this.職業 = occupation;
            this.電話番号 = phone;
            this.給料 = salary;
        }
    }
    
    public enum Occupation
    {
        医者,
        芸術家,
        教育者,
        エンジニア,
        重役,
        その他
    }
    
  2. クラスコンストラクタでプライベートメソッド InitializeFlexGridを作成し、次のコードを追加してレコードのコレクションを作成します。
            Dim data As New List(Of Customer)()
                 data.Add(new Customer("100001", "米国", "Jack Danson", 40, 102.03, _
    Occupation.重役, "1371234567", 400000000));
                data.Add(new Customer("100002", "中国", "Tony Tian", 32, 82.2, _
    Occupation.エンジニア, "1768423846", 500));
                data.Add(new Customer("100003", "イラン", "Larry Frommer", 15, 40.432, _
    Occupation.芸術家, "8473637486", 600));
                data.Add(new Customer("100004", "ドイツ", "Charlie Krause", 26, 69.32, _
    Occupation.医者, "675245438", 700));
                data.Add(new Customer("100005", "インド", "Mark Ambers", 51, 75.45, _
    Occupation.その他, "1673643842", 800));
    
    List<Customer> data = new List<Customer>();
     data.Add(new Customer("100001", "米国", "Jack Danson", 40, 102.03, _
     Occupation.重役, "1371234567", 400000000));
    data.Add(new Customer("100002", "中国", "Tony Tian", 32, 82.2, _
    Occupation.エンジニア, "1768423846", 500));
    data.Add(new Customer("100003", "イラン", "Larry Frommer", 15, 40.432, _
    Occupation.芸術家, "8473637486", 600));
    data.Add(new Customer("100004", "ドイツ", "Charlie Krause", 26, 69.32, _
    Occupation.医者, "675245438", 700));
    data.Add(new Customer("100005", "インド", "Mark Ambers", 51, 75.45, _
    Occupation.その他, "1673643842", 800));
    

先頭に戻る

InputPanel を追加する空のテンプレートの作成

InputPanel に行の詳細を表示するには、FlexGrid に追加した各レコードに対応する空のテンプレートを作成する必要があります。テンプレートを作成するには、各レコードの後に新しい行を追加し、その中のセルを結合して単一のセルにします。このセルを使用して入力パネルを表示します。

  1. メインコンストラクタでメソッド AddNewRowToFlexGridを作成して、各レコードの後に新しい行を追加します。
    'グリッド内の交互の行の後に行を追加し、その高さを0.1に設定します
    Private Sub AddNewRowToFlexGrid(flexGrid As C1FlexGrid)
        Dim i As Integer = flexGrid.Rows.Count - 1
        While i >= 0
            Dim rw As New Row()
            rw.AllowMerging = True
            flexGrid.Rows.Insert(i + 1, rw)
            rw.Height = 0.1
            i = i - 1
        End While
    End Sub
    
    //グリッド内の交互の行の後に行を追加し、その高さを0.1に設定します
    private void AddNewRowToFlexGrid(C1FlexGrid flexGrid)
    {
        for (int i = flexGrid.Rows.Count - 1; i >= 0; i = i - 1)
        {
            Row rw = new Row();
            rw.AllowMerging = true;
            flexGrid.Rows.Insert(i + 1, rw);
            rw.Height = 0.1;
        }
    }
    
  2. メインコンストラクタで AddNewRowToFlexGrid メソッドを作成して、各レコードの後に新しい行を追加します。
    '新しい行を追加するためにメソッドを初期化します
    AddNewRowToFlexGrid(FlexGrid)
    
    //新しい行を追加するためにメソッドを初期化します
    AddNewRowToFlexGrid(FlexGrid);
    
  3. クラス MergeManager を作成して、追加した行内のセルを結合します。
    'セルマージを実装するクラス
    Public Class MyMergeManager
        Implements IMergeManager
        Public Function GetMergedRange(grid As C1FlexGrid, _
                                       cellType__1 As CellType, range As CellRange) _
                                   As CellRange
            If grid.Rows(range.Row).DataItem Is Nothing Then
                If cellType__1 = CellType.Cell AndAlso range.Column >= 0 _
                    AndAlso range.Column < grid.Columns.Count Then
                    range.Column = 0
                    range.Column2 = grid.Columns.Count - 1
                End If
            End If
            Return range
        End Function
    End Class
    
    //セルマージを実装するクラス
    public class MyMergeManager : IMergeManager
    {
        public CellRange GetMergedRange(C1FlexGrid grid, 
            CellType cellType, CellRange range)
        {
            if (grid.Rows[range.Row].DataItem == null)
                if (cellType == CellType.Cell && range.Column >= 0 
                    && range.Column < grid.Columns.Count)
                {
                    range.Column = 0;
                    range.Column2 = grid.Columns.Count - 1;
                }
            return range;
        }
    }
    
  4. メインコンストラクタで結合マネージャーを初期化して、セルの結合を適用します。
    'マージマネージャを初期化してセルマージを処理します
    FlexGrid.MergeManager = New MyMergeManager()
    
    //マージマネージャを初期化してセルマージを処理します
    FlexGrid.MergeManager = new MyMergeManager();
    
  5. セルファクトリを処理するためのグローバル変数を初期化します。
    Private _cellFactory As MyCellFactory
    
    MyCellFactory _cellFactory;
    
  6. クラス CellFactoryを作成して、グリッドにカスタムセルを追加します。
    'グリッドセルをカスタマイズするためのCellFactoryクラス 
    Public Class MyCellFactory
        Inherits CellFactory
        Private _gr As Row
        Private _fg As C1FlexGrid
        Shared _bmpExpanded As ImageSource, _bmpCollapsed As ImageSource
        Public expandedList As New List(Of Integer)()
    
        Public Sub New()
            _bmpExpanded = ImageCell.GetImageSource("Expanded.png")
            _bmpCollapsed = ImageCell.GetImageSource("Collapsed.png")
        End Sub
    
        Public Overrides Sub _
            CreateCellContent(grid As C1FlexGrid, bdr As Border, rng As CellRange)
            MyBase.CreateCellContent(grid, bdr, rng)
            If _fg Is Nothing Then
                _fg = grid
            End If
    
            If _fg.Rows(rng.Row).DataItem IsNot Nothing Then
                If rng.Column = 0 Then
                    Dim customer As  _
                        Customer = TryCast(grid.Rows(rng.Row).DataItem, Customer)
    
                    If customer IsNot Nothing Then
                        bdr.Child = Nothing
                        Dim _nodeImage As Image
                        _gr = grid.Rows(rng.Row)
                        _nodeImage = New Image()
    
                        If expandedList.Contains(rng.Row) Then
                            _nodeImage.Source = _bmpExpanded
                        Else
                            _nodeImage.Source = _bmpCollapsed
                        End If
    
                        _nodeImage.Width = InlineAssignHelper(_nodeImage.Height, 9)
                        _nodeImage.VerticalAlignment = VerticalAlignment.Center
                        _nodeImage.Stretch = Stretch.None
                        bdr.Child = _nodeImage
                        AddHandler _nodeImage.PreviewMouseDown,_ 
                                           _AddressOf _nodeImage_PreviewMouseDown
                    Else
                        expandedList.Remove(rng.Row)
                        _fg.Rows(rng.Row + 1).Height = 0.1
                    End If
                End If
            ElseIf rng.Column = 0 AndAlso rng.ColumnSpan > 1 Then
                Dim customer As Customer = TryCast(grid.Rows(rng.Row - 1).DataItem, Customer)
                Dim panel As New C1InputPanel()
                panel.CurrentItem = customer
                grid.Rows(rng.Row).Tag = _
                    grid.Rows(rng.Row - 1).ActualHeight * (grid.Columns.Count + 1) * 1.22
                bdr.Child = panel
                bdr.Padding = New Thickness(1)
                grid.Rows(rng.Row).IsReadOnly = True
            End If
        End Sub
    
        'Expand / Collapseアイコンを切り替えて子行の可視性を変更するためのMouse Downイベントのハンドラ
        Private Sub _nodeImage_PreviewMouseDown(sender As Object, e As MouseButtonEventArgs)
            Dim _row As Integer = _
                Grid.GetRow(TryCast(VisualTreeHelper.GetParent(TryCast(e.OriginalSource,  _
                                                               Image)), Border))
            SetExpandCollapse(_row, sender)
        End Sub
    
        Public Sub SetExpandCollapse(_row As Integer, sender As Object)
            Dim image = TryCast(sender, Image)
            If expandedList.Contains(_row) Then
                _fg.Rows(_row + 1).Height = 0.1
                expandedList.Remove(_row)
                image.Source = _bmpCollapsed
            Else
                If _fg.Rows(_row + 1).Tag IsNot Nothing Then
                    _fg.Rows(_row + 1).Height = Double.Parse(_fg.Rows(_row + 1).Tag.ToString())
                End If
                expandedList.Add(_row)
                image.Source = _bmpExpanded
            End If
        End Sub
        Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
            target = value
            Return value
        End Function
    End Class
    
    //グリッドセルをカスタマイズするためのCellFactoryクラス
    public class MyCellFactory : CellFactory
    {
        Row _gr;
        C1FlexGrid _fg;
        static ImageSource _bmpExpanded, _bmpCollapsed;
        public List<int> expandedList = new List<int>();
    
        public MyCellFactory()
        {
            _bmpExpanded = ImageCell.GetImageSource("Expanded.png");
            _bmpCollapsed = ImageCell.GetImageSource("Collapsed.png");
        }
    
        public override void CreateCellContent
            (C1FlexGrid grid, Border bdr, CellRange rng)
        {
            base.CreateCellContent(grid, bdr, rng);
            if (_fg == null)
                _fg = grid;
    
            if (_fg.Rows[rng.Row].DataItem != null)
            {
                if (rng.Column == 0)
                {
                    Customer customer = 
                        (grid.Rows[rng.Row].DataItem as Customer);
    
                    if (customer != null)
                    {
                        bdr.Child = null;
                        Image _nodeImage;
                        _gr = grid.Rows[rng.Row];
                        _nodeImage = new Image();
    
                        if (expandedList.Contains(rng.Row))
                            _nodeImage.Source = _bmpExpanded;
                        else
                            _nodeImage.Source = _bmpCollapsed;
    
                        _nodeImage.Width = _nodeImage.Height = 9;
                        _nodeImage.VerticalAlignment = VerticalAlignment.Center;
                        _nodeImage.Stretch = Stretch.None;
                        bdr.Child = _nodeImage;
                        _nodeImage.PreviewMouseDown += _nodeImage_PreviewMouseDown;
                    }
                    else
                    {
                        expandedList.Remove(rng.Row);
                        _fg.Rows[rng.Row + 1].Height = 0.1;
                    }
                }
            }
            else if (rng.Column == 0 && rng.ColumnSpan > 1)
            {
                Customer customer = (grid.Rows[rng.Row - 1].DataItem as Customer);
                C1InputPanel panel = new C1InputPanel();
                panel.CurrentItem = customer;
                grid.Rows[rng.Row].Tag = grid.Rows[rng.Row - 1].ActualHeight *
                    (grid.Columns.Count + 1) * 1.22;
                bdr.Child = panel;
                bdr.Padding = new Thickness(1);
                grid.Rows[rng.Row].IsReadOnly = true;
            }
        }
    
        //Expand / Collapseアイコンを切り替えて子行の可視性を変更するためのMouse Downイベントのハンドラ
        void _nodeImage_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            int _row = Grid.GetRow
                (((VisualTreeHelper.GetParent(e.OriginalSource as Image) as Border)));
            SetExpandCollapse(_row, sender);
        }
    
        public void SetExpandCollapse(int _row, object sender)
        {
            var image = sender as Image;
            if (expandedList.Contains(_row))
            {
                _fg.Rows[_row + 1].Height = 0.1;
                expandedList.Remove(_row);
                image.Source = _bmpCollapsed;
            }
            else
            {
                if (_fg.Rows[_row + 1].Tag != null)
                {
                    _fg.Rows[_row + 1].Height = 
                        double.Parse(_fg.Rows[_row + 1].Tag.ToString());
                }
                expandedList.Add(_row);
                image.Source = _bmpExpanded;
            }
        }
      }
    
  7. メインコンストラクタで CellFactory クラスのオブジェクトを作成し、それを FlexGrid に割り当てます。
    'Cellfactoryオブジェクトを作成し、それをFlexGridに割り当てます
    _cellFactory = New MyCellFactory()
    FlexGrid.CellFactory = _cellFactory
    
    //Cellfactoryオブジェクトを作成し、それをFlexGridに割り当てます
    _cellFactory = new MyCellFactory();
    FlexGrid.CellFactory = _cellFactory;
    
  8. クラス ImageCellを作成し、画像(Resources フォルダに追加した画像)を取得してカスタムセルに追加します。
    '画像アイコンを適用するImageCellクラス
    Public MustInherit Class ImageCell
        Inherits StackPanel
        Private imgSrc As ImageSource
        Public Sub New(row As Row)
            If imgSrc Is Nothing Then
                imgSrc = GetImageSource(GetImageResourceName())
            End If
    
            Orientation = Orientation.Horizontal
            Dim img = New Image()
            img.Source = imgSrc
            img.Width = 25
            img.Height = 15
            img.VerticalAlignment = VerticalAlignment.Center
            img.Stretch = Stretch.None
            Children.Add(img)
        End Sub
    
        Public MustOverride Function GetImageResourceName() As String
        Public Shared Function GetImageSource(imageName As String) As ImageSource
            Dim imgConv = New ImageSourceConverter()
            Dim path As String = String.Format_
              ("pack://application:,,,/Integration-FlexGrid;component/Resources/{0}", _
                              imageName)
            Return DirectCast(imgConv.ConvertFromString(path), ImageSource)
        End Function
    End Class
    
    //画像アイコンを適用するImageCellクラス
    public abstract class ImageCell : StackPanel
    {
        ImageSource imgSrc;
        public ImageCell(Row row)
        {
            if (imgSrc == null)
            {
                imgSrc = GetImageSource(GetImageResourceName());
            }
    
            Orientation = Orientation.Horizontal;
            var img = new Image();
            img.Source = imgSrc;
            img.Width = 25;
            img.Height = 15;
            img.VerticalAlignment = VerticalAlignment.Center;
            img.Stretch = Stretch.None;
            Children.Add(img);
        }
    
        public abstract string GetImageResourceName();
    
        public static ImageSource GetImageSource(string imageName)
        {
            var imgConv = new ImageSourceConverter();
            string path = string.Format
                ("pack://application:,,,/Integration-FlexGrid;component/Resources/{0}",
                imageName);
            return (ImageSource)imgConv.ConvertFromString(path);
        }
    
    }
    

先頭に戻る

InputPanel と FlexGrid との統合

  1. FlexGrid を Customer クラスに連結し、コードでセル結合を有効にします(MainWindow.xaml.cs)。
    'FlexGridをCustomerにバインドし、セルのマージを許可します
    FlexGrid.ItemsSource = data
    FlexGrid.AllowMerging = AllowMerging.Cells
    
    //FlexGridをCustomerにバインドし、セルのマージを許可します
    FlexGrid.ItemsSource = data.ToList<顧客>();
    FlexGrid.AllowMerging = AllowMerging.Cells;
    
  2. いくつかのイベントをサブスクライブして、FlexGrid でのロード、選択の変更、列のソートを処理します。
    '/イベントを登録します
    AddHandler FlexGrid.Loaded, AddressOf FlexGrid_Loaded
    AddHandler FlexGrid.SelectionChanging,AddressOf FlexGrid_SelectionChanging
    AddHandler FlexGrid.SortedColumn, AddressOf FlexGrid_SortedColumn
    
    //イベントを登録します
    FlexGrid.Loaded += FlexGrid_Loaded;
    FlexGrid.SelectionChanging += FlexGrid_SelectionChanging;
    FlexGrid.SortedColumn += FlexGrid_SortedColumn;
    
  3. サブスクライブしたイベントのハンドラを作成します。
    'Loadedのハンドラ、 Selection Changing およびSorted Column のイベント
    Private Sub FlexGrid_Loaded(sender As Object, e As RoutedEventArgs)
        FlexGrid.AutoSizeColumns(1, FlexGrid.Columns.Count - 1, 10)
    End Sub
    
    Private Sub FlexGrid_SelectionChanging(sender As Object, e As CellRangeEventArgs)
        Dim inputPanel As C1InputPanel = Nothing
        GetInputPanelElement(e.Panel, inputPanel)
        If inputPanel IsNot Nothing AndAlso e.CellRange.Row Mod 2 = 1 Then
            e.Cancel = True
        End If
    End Sub
    
    Private Sub FlexGrid_SortedColumn(sender As Object, e As CellRangeEventArgs)
        Dim flexGrid As C1FlexGrid = TryCast(sender, C1FlexGrid)
        AddNewRowToFlexGrid(flexGrid)
    End Sub
    
    //Loadedのハンドラ、 Selection Changing およびSorted Column のイベント
    private void FlexGrid_Loaded(object sender, RoutedEventArgs e)
    {
        FlexGrid.AutoSizeColumns(1, FlexGrid.Columns.Count - 1, 10);
    }
        
    private void FlexGrid_SelectionChanging(object sender, CellRangeEventArgs e)
    {
        C1InputPanel inputPanel = null;
        GetInputPanelElement(e.Panel, ref inputPanel);
        if (inputPanel != null && e.CellRange.Row % 2 == 1)
        {
            e.Cancel = true;
        }
    
    }
    
    private void FlexGrid_SortedColumn(object sender, CellRangeEventArgs e)
    {
        C1FlexGrid flexGrid = sender as C1FlexGrid;
        AddNewRowToFlexGrid(flexGrid);
    }
    

先頭に戻る

関連トピック