ComponentOne InputPanel for WPF
In This Topic
    Integration with FlexGrid
    In This Topic

    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