! 제품 버전을 정확하게 입력해 주세요.
제품 버전이 정확하게 기재되어 있지 않은 경우,
최신 버전을 기준으로 안내 드리므로
더욱 빠르고 명확한 안내를 위해
제품 버전을 정확하게 입력해 주세요!

WinForms Datagrid에 아웃라인 TreeView를 추가하는 방법 > 블로그 & Tips

본문 바로가기

ComponentOne

블로그 & Tips

WinForms Datagrid에 아웃라인 TreeView를 추가하는 방법

페이지 정보

작성자 GrapeCity 작성일 2022-09-14 13:30 조회 2,497회 댓글 0건

본문

WinForms용 FlexGrid 컨트롤의 고유하고 많이 사용되는 기능 중 하나는 구조화되지 않은 일반 데이터에 계층 구조 그룹화를 추가하는 기능입니다.


이 목표를 달성하기 위해 C1FlexGrid에는 노드 행의 개념이 도입되었습니다. 노드 행은 다음 사항을 제외하고, 일반 행과 거의 동일합니다.


  • 노드 행은 데이터에 바인딩되지 않습니다. 그리드가 데이터 소스에 바인딩되는 경우 각 일반 행은 데이터 소스의 한 항목에 해당합니다. 노드 행은 그렇지 않습니다. 대신 노드 행은 비슷한 데이터가 포함된 일반 행을 그룹화하기 위해 존재합니다.

  • 노드 행은 축소하거나 확장할 수 있습니다. 노드 행이 축소된 경우 모든 해당 데이터와 하위 노드가 숨겨집니다. 아웃라인 트리가 표시되는 경우 사용자가 마우스나 키보드를 사용하여 노드를 축소하고 확장할 수 있습니다. 아웃라인 트리가 표시되지 않으면 코드를 사용해서만 노드를 확장하거나 축소할 수 있습니다.


예를 들어 제품, 국가, 도시, 및 판매 금액을 표시하는 그리드가 있다고 가정하겠습니다. 이 일반적인 그리드는 일반적으로 다음과 같은 모습입니다.


그리드


모든 정보가 포함되어 있지만 각 국가 또는 고객의 총 판매액을 확인하기는 어렵습니다.


C1FlexGrid의 아웃라인 기능을 사용하여 국가별(수준 0)로 데이터를 그룹화하고, 각 국가 내 도시별(수준 1)로 그룹화한 다음, 각 도시 내 제품별(수준 2)로 그룹화할 수 있습니다.


다음은 아웃라인을 추가한 후의 동일한 그리드입니다.


아웃라인 그리드


이 그리드에는 이전 그리드와 동일한 정보가 표시되지만(동일한 데이터에 바인딩됨), 각 노드에 노드 아래에 있는 데이터의 요약이 포함되는 트리가 추가됩니다.

노드를 축소하여 요약만 표시하거나 확대하여 세부 정보를 표시할 수 있습니다. 각 노드에 두 개 이상의 열에 대한 요약을 표시할 수 있습니다(이 경우 총 판매 단위 수 및 총액).

이 블로그에서는 일반 데이터 바인딩 그리드를 더 풍부한 아웃라인 그리드로 전환하는 방법을 보여줍니다.

ComponentOne에서 제공하는 다른 기능에 관심이 있으십니까?

지금 무료 평가판을 다운로드하십시오.!



아웃라인 만들기


이 섹션에서는 그룹화 및 부분합 메서드와 같이 구조화되지 않은 일반 데이터로 쉽게 아웃라인 또는 트리 그리드를 제공할 수 있도록 FlexGrid에서 기본으로 제공하는 여러 방법에 대해 알아봅니다.


다음 섹션에서는 Flexgrid에서 수동으로 아웃라인을 만드는 방법을 설명합니다.



그룹화


그룹화는 그리드 데이터를 공통적인 열 값을 갖는 행이 그룹으로 표시되는 트리와 같은 구조로 구성하는 것을 가리킵니다. 각 그룹 헤더는 노드 행이며 그룹 헤더를 사용하면 그룹을 확장하거나 축소하여 그리드 데이터를 더 쉽게 분석할 수 있습니다. FlexGrid에서는 코드 및 열 상황에 맞는 메뉴 및 FlexGridGroupPanel 컨트롤을 통한 사용자 상호 작용을 통해 그룹화를 실행할 수 있습니다.


위에 표시된 아웃라인 그리드를 만들려면 비용 및 수량 열의 집계를 표시하고 국가 및 도시별로 데이터를 그룹화해야 합니다.


집계의 경우 열의 Aggregate 속성을 AggregateEnum 값으로 설정할 수 있으며, 이에 따라 FlexGrid에서 그룹 헤더에 집계 값을 표시합니다. 위에 표시된 그리드의 경우, 아래의 코드를 사용하여 수량과 비용 열의 합을 표시합니다.


c1FlexGrid1.Cols["Quantity"].Aggregate = C1.Win.C1FlexGrid.AggregateEnum.Sum;
c1FlexGrid1.Cols["Cost"].Aggregate = C1.Win.C1FlexGrid.AggregateEnum.Sum;


이제 집계를 설정했으므로, 아래의 코드를 사용하여 국가 및 도시 열 기준 그룹화를 추가할 수 있습니다.


c1FlexGrid1.HideGroupedColumns = true;
c1FlexGrid1.GroupDescriptions = new List<C1.Win.C1FlexGrid.GroupDescription> {
               new C1.Win.C1FlexGrid.GroupDescription("Country"),
               new C1.Win.C1FlexGrid.GroupDescription("City") };


이 그리드에 위에 표시된 그리드와 동일한 아웃라인이 표시됩니다.


그룹화에 사용되는 여러 메서드에 대한 자세한 내용은 FlexGrid 문서를 참고하세요.



부분합 메서드 사용


C1FlexGrid의 부분합 메서드를 사용하여 트리를 만들 수도 있습니다. 부분합 메서드는 또한 단일 단계로 그룹화를 수행하고 집계를 추가합니다. 아래의 코드는 부분합 메서드를 사용하여 위와 동일한 목표를 달성하는 방법을 보여줍니다.

// group and total by country and city
_flex.Subtotal(C1.Win.C1FlexGrid.AggregateEnum.Sum, 0, "Country", "Cost");
_flex.Subtotal(C1.Win.C1FlexGrid.AggregateEnum.Sum, 0, "Country", "Quantity");
​
_flex.Subtotal(C1.Win.C1FlexGrid.AggregateEnum.Sum, 1, "City", "Cost");
_flex.Subtotal(C1.Win.C1FlexGrid.AggregateEnum.Sum, 1, "City", "Quantity");
​
// hide columns that are grouped on  
// (they only have duplicate values which already appear on the tree nodes)  
// (but do not make them invisible, that would also hide the node text)  
_flex.Cols["Country"].Width = 0;
_flex.Cols["City"].Width = 0;
_flex.AllowMerging = C1.Win.C1FlexGrid.AllowMergingEnum.Nodes;
           
           
//show outline tree
_flex.Tree.Column = 0;
_flex.Tree.Show(1);


부분합 메서드는 매우 편리하고 유연합니다. 이 메서드에는 그룹화하여 색인 또는 이름별로 합계를 구해야 하는 열, 삽입하는 노드 행에 캡션을 포함해야 하는지 여부, 그룹화를 수행하는 방법 등을 지정할 수 있는 여러 오버로드가 있습니다.


부분합, 부분합 사용자 지정 등에 관한 자세한 내용은 FlexGrid 문서를 참고하세요.



수동으로 아웃라인 만들기


노드 행 만들기


위에 설명된 아웃라인을 만드는 메서드와 별도로, 수동으로 노드 행을 만들어 그리드에서 수동으로 아웃라인을 만들 수도 있습니다. 노드 행은 세 가지 방법으로 만들 수 있습니다.


  • Rows.InsertNode 메서드를 사용합니다. 이는 지정된 인덱스에 새로운 노드 행을 삽입합니다. 노드 행이 만들어지면 다른 모든 행과 같이 이를 사용할 수 있습니다(각 열에 데이터 설정, 스타일 적용 등). 이는 합계를 삽입하고 아웃라인을 빌드하는 낮은 수준의 방법입니다. 대부분의 컨트롤과 유연성을 제공하며 이는 아래에 설명되어 있습니다.

  • 그리드가 바인딩 해제되는 경우 IsNode 속성을 true로 설정하여 일반 행을 노드 행으로 변환할 수 있습니다. 이는 그리드가 바인딩 해제되는 경우에만 적용됩니다. 데이터가 바인딩된 일반 행을 노드로 변환하려고 하면 그리드에서 예외 사항이 발생됩니다.


아래 코드는 주어진 열에서 동일한 값을 그룹화하여 노드 행을 삽입하는 GroupBy 메서드를 구현하는 방법을 보여줍니다.

void GroupBy(string columnName, int level)
      {
           object current = null;
           for (int r = _flex.Rows.Fixed; r < _flex.Rows.Count; r++)
          {
               if (!_flex.Rows[r].IsNode)
              {
                   var value = _flex[r, columnName];
                   if (!object.Equals(value, current))
                  {
                       // value changed: insert node  
                       _flex.Rows.InsertNode(r, level);
                       
                       //set subtotal0 style to the node row
                       _flex.Rows[r].Style = _flex.Styles[CellStyleEnum.Subtotal0];
                       
                       // show group name in first scrollable column  
                       _flex[r, _flex.Cols.Fixed] = value;
​
                       // update current value  
                       current = value;
                  }
              }
          }
      }


코드는 모든 열을 스캔하여 여러 노드 수준을 추가하기 위해 호출할 수 있도록 기존 노드 행을 건너뛰고 그룹화되는 열의 현재 값을 추적합니다. 현재 값이 변경되면 노드 행은 첫 번째 스크롤 가능한 열에서 새로운 항목을 표시합니다.


이제 첫 번째 예제와 동일한 그리드를 만들기 위해 다음을 호출하여 2단계 수준 아웃라인을 만들도록 이 메서드를 사용할 수 있습니다.


private void groupByCountryCity_Click(object sender, EventArgs e)
      {
           GroupBy("Country", 0);
           GroupBy("City", 1);
      }


꽤 간단하지만 몇 가지 주의할 사항이 있습니다.


  • 메서드에서는 아웃라인 구조에 따라 데이터가 정렬된다고 가정합니다. 이 예제에서는 국가별 대신 제품별로 데이터가 정렬되었을 때 아웃라인에 각 국가에 대한 여러 수준-0 노드가 있으며 이는 원하던 바가 아닙니다.

  • 또한 GroupBy 메서드는 많은 행을 삽입할 수 있으며 이로 인해 그리드가 깜박입니다. 이를 방지하려면 업데이트 및 완료되었을 때 EndUpdate 전 일반적으로 BeginUpdate 메서드를 사용합니다.

  • 노드 행이 예상대로 만들어졌다는 것을 알아챘을 수 있지만 아웃라인 트리는 표시되지 않으므로 노드를 확장하고 축소할 수 없습니다. 트리 열을 설정할 것이며 이는 나중에 "아웃라인 트리" 섹션에서 설명합니다.


이러한 문제를 처리하려면 아웃라인을 만드는 코드를 다음과 같이 다시 작성해야 합니다.


private void groupByCountryCity_Click(object sender, EventArgs e)
{
           _flex.BeginUpdate();
           ResetBinding();
           GroupBy("Country", 0);
           GroupBy("City", 1);
           _flex.EndUpdate();
}
private void ResetBinding()
{
           // re-bind grid  
           _flex.DataSource = null;
           _flex.DataSource = _ordersData;
           _flex.Tree.Column = 0;
           // resize columns to fit their content  
           _flex.AutoSizeCols();
}


소계 추가


지금까지 노드 행 및 아웃라인 트리 생성에 대해 다루었습니다. 하지만 아웃라인을 유용하게 하려면 노드 행은 포함된 데이터의 요약 정보를 포함해야 합니다.

그룹화 또는 소계 메서드를 사용하여 아웃라인 트리를 만들면 소계가 자동으로 추가됩니다.

위에서 설명한 대로 Rows.InsertNode 메서드를 사용하여 아웃라인 트리를 만들었다고 가정해보면 집계 메서드를 사용하여 행의 각 그룹에 대한 소계를 계산하고 결과를 노드 행에 직접 삽입해야 합니다.


아래 나열된 소계 메서드는 이를 수행하는 방법을 보여줍니다.


void AddSubtotals(int level, string colName)
      {
           // get column we are going to total on  
           int colIndex = _flex.Cols.IndexOf(colName);
​
           // scan rows looking for nodes at the right level  
           for (int r = _flex.Rows.Fixed; r < _flex.Rows.Count; r++)
          {
               if (_flex.Rows[r].IsNode)
              {
                   var node = _flex.Rows[r].Node;
                   if (node.Level == level)
                  {
                       // found a node, calculate the sum of extended price  
                       var range = node.GetCellRange();
                       var sum = _flex.Aggregate(AggregateEnum.Sum,
                           range.r1, colIndex, range.r2, colIndex,
                           AggregateFlags.ExcludeNodes);
​
                       // show the sum on the grid  
                       // (will use the column format automatically)  
                       _flex[r, colIndex] = sum;
                  }
              }
          }
      }


이 메서드는 노드 행을 찾는 그리드 행을 스캔합니다. 원하는 수준의 노드 행을 찾으면 메서드는 Node.GetCellRange 메서드를 사용하여 노드의 하위 행을 검색합니다. 그런 다음 집계 메서드를 사용하여 전체 범위의 대상 열에서 값의 합계를 계산합니다.


집계 호출에는 기존 노드의 이중 계산을 방지하기 위한 ExcludeNodes 플래그가 포함됩니다. 소계를 계산하고 나면 usual _flex[row, col] 인덱서와 함께 노드 행의 셀에 할당됩니다. 이 예제에서는 수량 및 비용 열에 합계를 추가하겠습니다. 집계 외에도 평균, 최대값, 최소값 등과 같은 다른 집계를 추가할 수 있습니다.


이 메서드를 사용하여 노드 행, 아웃라인 트리 및 소계로 전체 아웃라인을 만들 수 있습니다.


private void groupByCountryCity_Click(object sender, EventArgs e)
      {
           _flex.BeginUpdate();
           // restore original sort (by Country, City, SalesPerson)  
           ResetBinding();
​
           // group by Country, City  
           GroupBy("Country", 0); // group by country (level 0)  
           GroupBy("City", 1);    // group by city (level 1)  
​
           // hide columns that we grouped on  
           // (they only have duplicate values which already appear on the tree nodes)  
           // (but don't make them invisible, that would also hide the node text)  
           _flex.Cols["Country"].Width = 0;
           _flex.Cols["City"].Width = 0;
​
           // allow node content to spill onto next cell  
           _flex.AllowMerging = AllowMergingEnum.Nodes;
​
           // add totals per Country, City  
           AddSubtotals(0, "Cost");  // cost per country (level 0)  
           AddSubtotals(0, "Quantity");       // quantity per country (level 0)  
           AddSubtotals(1, "Cost");  // cost per city (level 1)  
           AddSubtotals(1, "Quantity");       // quantity per city (level 1)  
​
           // show outline tree  
           _flex.Tree.Column = 0;
           _flex.AutoSizeCol(_flex.Tree.Column);
           _flex.Tree.Show(1);
           _flex.EndUpdate();
      }


결과는 다음과 비슷할 것입니다.


트리


여기에서 샘플을 참조할 수 있습니다.


아웃라인 트리


아웃라인 트리는 일반 TreeView 컨트롤에서 볼 수 있는 것과 같습니다. 각 노드 행 옆에 축소/확장 아이콘과 함께 들여쓴 구조를 표시하므로 사용자는 세부 정보의 원하는 수준을 볼 수 있도록 아웃라인을 확장하고 축소할 수 있습니다.


아웃라인 트리는 Tree.Column 속성에서 정의하는 모든 열에서 표시될 수 있으므로 위의 섹션에서 아웃라인 트리를 표시하는 Tree.Column 속성을 사용한 것을 이제 알아챘을 수 있습니다. 기본적으로 이 속성은 -1로 설정되어 트리가 전혀 표시되지 않습니다.


트리 속성은 아웃라인 트리를 사용자 정의하는 데 사용되는 몇 가지 메서드 및 속성을 노출하는 GridTree 개체에 참조를 반환합니다. 주요 항목은 아래에 나열되어 있습니다.


  • : 아웃라인 트리를 포함하는 열의 인덱스를 가져오거나 설정합니다. 이 속성을 -1로 설정하면 사용자에게서 아웃라인 트리가 숨겨집니다.

  • 들여쓰기: 픽셀에서 근접 노드 수준 간에 들여쓰기를 가져오거나 설정합니다. 들여쓰기 수준이 높아질수록 트리는 더 넓어집니다.

  • 스타일: 표시할 아웃라인 트리의 유형을 가져오거나 설정합니다. 이 속성을 사용하여 사용자가 전체 트리를 축소/확장할 수 있도록 상단에 트리가 버튼 막대를 표시할지 여부, 줄 및/또는 기호를 표시할지 여부 및 트리를 데이터 행 및 노드 행에 연결하여 줄을 표시할지 여부를 결정할 수 있습니다.

  • LineColor: 트리의 연결 줄 색상을 가져오거나 설정합니다.

  • LineStyle: 트리의 연결 줄 스타일을 가져오거나 설정합니다.


예를 들어 다음 줄을 포함하도록 예제 아웃라인 트리의 코드를 변경합니다.

// show outline tree  
_flex.Tree.Column = 0;  
_flex.Tree.Style = TreeStyleFlags.CompleteLeaf;  
_flex.Tree.LineColor = Color.Blue;  
_flex.Tree.Indent = 30;


아웃라인 트리는 다음과 같이 변경됩니다.

아웃라인 트리


왼쪽 상단 셀에 "1", "2" 및 "*"의 레이블이 지정된 버튼을 확인하십시오.

이러한 버튼을 클릭하면 전체 트리가 해당 수준으로 축소되거나 확장됩니다.


또한 트리를 일반 행("Boston Crab Meat", "Gnocchi di nonna Alice" 등)과 노드 행에 연결하여 들여쓰기와 줄이 더욱 넓어집니다.



아웃라인 유지보수


지금까지 높은 수준의 그룹화와 소계 메서드 및 더 낮은 수준의 Rows.InsertNode와 집계 메서드를 사용하여 트리 및 합계로 아웃라인을 만드는 방법에 대해 알아봤습니다.


이 시점에서 아웃라인 트리는 데이터를 기반으로 만들어지지만 어떤 방식으로든 바인딩되지 않고 그리드 또는 데이터에 변경 사항이 있는 경우 자동으로 유지되지 않는다는 점을 기억하는 것이 중요합니다.


예를 들어 사용자가 "ExtendedPrice" 열에서 값을 수정하는 경우 소계는 자동으로 업데이트되지 않습니다. 사용자가 그리드를 정렬하는 경우 데이터는 새로 고쳐지며 소계는 사라집니다.


아웃라인을 유지하는 데는 두 가지의 일반적인 방법이 있습니다.


  • 사용자가 아웃라인을 무효화하는 변경을 하지 않도록 방지합니다. 이는 가장 쉬운 옵션입니다. 그리드의 AllowEditing, AllowDraggingAllowSorting 속성을 false로 설정하고 아웃라인에 영향을 끼치는 변경 사항을 방지합니다.

  • 데이터 또는 그리드에 변경 사항이 있는 경우에는 아웃라인을 업데이트합니다. 처리기를 그리드의 AfterDataRefresh, AfterSortAfterEdit 이벤트에 연결하고 아웃라인을 적절하게 다시 생성합니다.


옵션 2는 동적 데이터 분석에 빠르고 단순한 도구를 제공하므로 일반적으로 더욱 흥미롭습니다.


이 접근 방식은 C1FlexGrid와 제공된 분석 샘플로 보여 줍니다. 샘플은 초기 아웃라인을 만들고 사용자가 열을 다시 정렬할 수 있도록 합니다.


열 순서가 변경되면 샘플은 자동으로 데이터를 다시 정렬하고 아웃라인을 다시 만듭니다.


사용자는 국가, 제품, 판매인 등을 기준으로 판매를 보여주는 간단한 보고서를 쉽게 만들 수 있습니다.



노드 클래스 사용


노드 클래스는 아웃라인 트리를 만들고 관리하는 데 사용할 수 있는 여러 메서드와 속성을 제공합니다. 이러한 많은 메서드와 속성은 표준 TreeView 개체 모델을 기준으로 하므로 대부분의 개발자에게 익숙해야 합니다.


노드 개체를 가져오려면 다음 중에서 수행할 수 있습니다. Rows.InsertNode 메서드의 반환 값 사용:

var node = _flex.Rows.InsertNode(index, level);


또는 행의 노드 속성을 사용하여 기존 행의 노드를 검색할 수 있습니다.

var node = _flex.Rows[index].IsNode
   ? _flex.Rows[index].Node
  : null;


또 다른 방법으로 노드 개체가 있으면 다음 속성 및 메서드를 사용하여 조작할 수 있습니다.


  • 수준: 아웃라인 트리의 노드 수준을 가져오거나 설정

  • 데이터: Node.Row 및 Tree.Column에서 정의한 셀에서 값을 가져오거나 설정

  • 이미지: Node.Row 및 Tree.Column에서 정의한 셀에서 이미지를 가져오거나 설정

  • 선택됨: Node.Row 및 Tree.Column에서 정의한 셀의 선택 상태를 가져오거나 설정

  • 축소됨/확장됨: 노드의 축소됨/확장됨 상태를 가져오거나 설정


다음 메서드를 사용하여 아웃라인 구조를 살펴볼 수도 있습니다.

  • GetCellRange(): 이 노드에 속한 행의 범위를 설명하는 CellRange 개체 가져오기

  • 하위: 이 노드 아래 하위 노드의 수를 가져옵니다.

  • 노드: 이 노드의 하위 노드가 포함된 노드 배열을 가져옵니다.

  • GetNode: 이 노드에 주어진 관계로 노드 가져오기(상위, 첫 번째 하위, 다음 형제 등)


위의 논의는 데이터를 제공하는 데이터 소스에 그리드가 연결된 바인딩된 시나리오에 중점을 두었습니다.


바인딩 해제된 시나리오에서 트리 및 아웃라인을 만들 수도 있습니다. IsNode 속성을 true로 설정하여 행을 노드 행으로 변환할 수 있으므로 더욱 간단해집니다. 그리드가 바인딩 해제되면 표시된 모든 데이터를 소유하며 데이터 소스에서 데이터를 소유하는 경우 불가능한 일을 해낼 수 있습니다.


예를 들어 C1FlexGrid에서 제공한 TreeNode 샘플에서 보여준 대로 Node.Move 메서드를 사용하여 트리 주변에서 노드를 이동할 수 있습니다. 바운딩 해제된 그리드에서 노드를 사용하는 것은 일반 TreeView 컨트롤에서 노드를 사용하는 것과 같습니다.


여기에서 FlexGrid 제품 샘플을 확인하고 여기에서 문서를 확인할 수 있습니다.





지금 바로 ComponentOne을 다운로드하여 직접 테스트해보세요!

 
  • 페이스북으로 공유
  • 트위터로  공유
  • 링크 복사
  • 카카오톡으로 보내기

댓글목록

등록된 댓글이 없습니다.

메시어스 홈페이지를 통해 제품에 대해서 더 자세히 알아 보세요!
홈페이지 바로가기

태그1

인기글

더보기
  • 인기 게시물이 없습니다.
메시어스 홈페이지를 통해 제품에 대해서 더 자세히 알아 보세요!
홈페이지 바로가기
이메일 : sales-kor@mescius.com | 전화 : 1670-0583 | 경기도 과천시 과천대로 7길 33, 디테크타워 B동 1107호 메시어스(주) 대표자 : 허경명 | 사업자등록번호 : 123-84-00981 | 통신판매업신고번호 : 2013-경기안양-00331 ⓒ 2024 MESCIUS inc. All rights reserved.