ComponentOne InputPanel for WPF
Integration with FlexGrid

The integration of InputPanel is more elaborate in case of FlexGrid as you need to create an empty template and cell factory objects to display the row details.

The following image shows an InputPanel integrated with a FlexGrid.

Perform the following steps to integrate InputPanel with FlexGrid:
  1. Set up the application
  2. Create a data source
  3. Create an empty template to add InputPanel
  4. Integrate InputPanel with template

Back to Top

Set up the application

  1. Create a WPF application and add a FlexGrid control to the designer.
  2. Set the column width and minimum row height in XAML view.
    XAML
    Copy Code
    <Grid>
        <c1:C1FlexGrid x:Name="FlexGrid" MinRowHeight="1">
            <c1:C1FlexGrid.Columns>
                <c1:Column Width="20" IsReadOnly="True"/>
            </c1:C1FlexGrid.Columns>             
        </c1:C1FlexGrid>
    </Grid>
    
  3. Add a new folder, Resources, and add two images in it for expanding and collapsing the integrated InputPanel.

Back to Top

Create a data source

  1. Switch to the code view and create a Customer class to add records into the InputPanel, and an enumeration to accept values for Occupation field.
    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 Country() 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 Name() 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 Age() 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 Weight() 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 Occupation() 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 Phone() 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 Salary() 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 = country
            Me.Name = name
            Me.Age = age
            Me.Weight = weight
            Me.Occupation = occupation
            Me.Phone = phone
            Me.Salary = salary
        End Sub
    End Class
    
    Public Enum Occupation
        Doctor
        Artist
        Educator
        Engineer
        Executive
        Other
    End Enum
    
    public class Customer
    {
        public string ID { get; set; }
        public string Country { get; set; }
    
        public string Name { get; set; }
    
    
        public int Age { get; set; }
        public double Weight { get; set; }
        public Occupation Occupation { get; set; }
        public string Phone { get; set; }
        public int Salary { 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 = country;
            this.Name = name;
            this.Age = age;
            this.Weight = weight;
            this.Occupation = occupation;
            this.Phone = phone;
            this.Salary = salary;
        }
    }
    
    public enum Occupation
    {
        Doctor,
        Artist,
        Educator,
        Engineer,
        Executive,
        Other
    }
    
  2. Create a private method, InitializeFlexGrid, in the class constructor and add the following code to create a collection of records.
    Dim data As New List(Of Customer)()
    data.Add(New Customer("100001", "United States", "Jack Danson", 40, 102.03, _
                          Occupation.Executive, _
        "1371234567", 400000000))
    data.Add(New Customer("100002", "China", "Tony Tian", 32, 82.2, _
                          Occupation.Engineer, _
        "1768423846", 500))
    data.Add(New Customer("100003", "Iran", "Larry Frommer", 15, 40.432, _
                          Occupation.Artist, _
        "8473637486", 600))
    data.Add(New Customer("100004", "Germany", "Charlie Krause", 26, 69.32, _
                          Occupation.Doctor, _
        "675245438", 700))
    data.Add(New Customer("100005", "India", "Mark Ambers", 51, 75.45, _
                          Occupation.Other, _
        "1673643842", 800))
    
    List<Customer> data = new List<Customer>();
    data.Add(new Customer("100001", "United States", "Jack Danson",
        40, 102.03, Occupation.Executive, "1371234567", 400000000));
    data.Add(new Customer("100002", "China", "Tony Tian", 
        32, 82.2, Occupation.Engineer, "1768423846", 500));
    data.Add(new Customer("100003", "Iran", "Larry Frommer", 
        15, 40.432, Occupation.Artist, "8473637486", 600));
    data.Add(new Customer("100004", "Germany", "Charlie Krause", 
        26, 69.32, Occupation.Doctor, "675245438", 700));
    data.Add(new Customer("100005", "India", "Mark Ambers", 
        51, 75.45, Occupation.Other, "1673643842", 800));
    

Back to Top

Create an empty template to add InputPanel

To display row details in an InputPanel, you need to create an empty template corresponding to each record that you add in FlexGrid. The template can be created by adding a new row after every record and merging the cells to form a single cell, which can be used to display an input panel.

  1. Create a method, AddNewRowToFlexGrid, outside the main constructor to add a new row after every record.
    'Add a row after every row in the grid and set its height to 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
    
    //Add a row after every row in the grid and set its height to 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. Invoke the AddNewRowToFlexGrid method in the main constructor to add a new row after every record.
    'Initialize a method to add new row
    AddNewRowToFlexGrid(FlexGrid)
    
    //Initialize a method to add new row
    AddNewRowToFlexGrid(FlexGrid);
    
  3. Create a class, MergeManager, to merge the cells of the added row.
    'Class that implements cell merging 
    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
    
    //Class that implements cell merging
    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. Initialize a merge manager in the main constructor to apply cell merging.
    'Initialize a merge manager to handle cell merging
    FlexGrid.MergeManager = New MyMergeManager()
    
    //Initialize a merge manager to handle cell merging
    FlexGrid.MergeManager = new MyMergeManager();
    
  5. Initialize a global variable for handling cell factory.
    Private _cellFactory As MyCellFactory
    
    MyCellFactory _cellFactory;
    
  6. Create a class, CellFactory, to add custom cells in the grid.
    'CellFactory class to customize grid cells 
    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
    
        'Handler for Mouse Down event to toggle Expand/Collapse icon and change child row visibility
        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 class to customize grid cells
    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;
            }
        }
    
        //Handler for Mouse Down event to toggle Expand/Collapse icon and change child row visibility
        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. Create an object of the CellFactory class and assign it to FlexGrid in the main constructor.
    'Create a cell factory object and assign it to FlexGrid
    _cellFactory = New MyCellFactory()
    FlexGrid.CellFactory = _cellFactory
    
    //Create a cell factory object and assign it to FlexGrid
    _cellFactory = new MyCellFactory();
    FlexGrid.CellFactory = _cellFactory;
    
  8. Create a class, ImageCell, to fetch and add images (added in the Resources folder) in the custom cells.
    'ImageCell class to apply image icons
    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 class to apply image icons   
    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);
        }
    
    }
    

Back to Top

Integrate InputPanel with FlexGrid

  1. Bind the FlexGrid to Customer class and enable cell merging in code (MainWindow.xaml.cs).
    'Bind FlexGrid to Customer and allow cell merging
    FlexGrid.ItemsSource = data
    FlexGrid.AllowMerging = AllowMerging.Cells
    
    //Bind FlexGrid to Customer and allow cell merging 
    FlexGrid.ItemsSource = data.ToList<Customer>();
    FlexGrid.AllowMerging = AllowMerging.Cells;
    
  2. Subscribe events to handle load, selection change, and sorted columns in FlexGrid.
    'Subscribe events
    AddHandler FlexGrid.Loaded, AddressOf FlexGrid_Loaded
    AddHandler FlexGrid.SelectionChanging, AddressOf FlexGrid_SelectionChanging
    AddHandler FlexGrid.SortedColumn, AddressOf FlexGrid_SortedColumn
    
    //Subscribe events
    FlexGrid.Loaded += FlexGrid_Loaded;
    FlexGrid.SelectionChanging += FlexGrid_SelectionChanging;
    FlexGrid.SortedColumn += FlexGrid_SortedColumn;
    
  3. Create handlers for the subscribed events.
    'Handlers for Loaded, Selection Changing and Sorted Column events 
    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
    
    //Handlers for Loaded, Selection Changing and Sorted Column events 
    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);
    }
    

Back to Top

See Also