티스토리 뷰

반응형

C1FlexGrid에 Custom MergeManager를 만들어서 사용하는 방법에 대한 예제가 모두 grid[r,c]에서 값을 가지고 와서 비교하도록 되어 있는데, 이 부분이 성능에 많은 영향을 줍니다. 


그래서, CollectionView에서 데이터를 직접 찾아서 비교하는 방법으로 성능을 50% 이상 올릴 수 있는 방법을 셈플로 만들어 보았습니다.


위의 성능 프로파일러만 보더라도 확연히 차이가 나는 것을 알 수 있습니다.


MainWindow.xaml


<Window x:Class="FlexGridMergeManagerSampleForWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:FlexGridMergeManagerSampleForWPF"
        xmlns:c1="http://schemas.componentone.com/winfx/2006/xaml"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <Button Content="Using grid[r,c]" Click="ButtonBase_OnClick" />
            <Button Content="Using CollectionView" Click="ButtonBase_OnClick" />
        </StackPanel>
        <c1:C1FlexGrid x:Name="FlexGrid" Grid.Row="1"
                       HeadersVisibility="All"
                       AutoGenerateColumns="False"
                       AllowMerging="All"
                       GridLinesVisibility="All"
                       GridLinesBrush="LightGray"
                       FrozenLinesBrush="#FF2A4C80"
                       ColumnHeaderBackground="#FFDBE1E9"
                       RowHeaderBackground="#FFDBE1E9"
                       TopLeftCellBackground="#FFBAD2F5"
                       IsReadOnly="True"
                       AllowResizing="Both"
                       AllowSorting="True"
                       ShowMarquee="True"
                       ClipboardCopyMode="ExcludeHeader">
            <c1:C1FlexGrid.Columns>
                <c1:Column Binding="{Binding OrderID}" AllowMerging="False" />
                <c1:Column Binding="{Binding ProductID}" AllowMerging="True" />
                <c1:Column Binding="{Binding ProductName}" AllowMerging="True"/>
                <c1:Column Binding="{Binding UnitPrice}" AllowMerging="True" />
                <c1:Column Binding="{Binding Quantity}" AllowMerging="True" />
                <c1:Column Binding="{Binding Discount}" AllowMerging="True" />
                <c1:Column Binding="{Binding ExtendedPrice}" AllowMerging="True" />
            </c1:C1FlexGrid.Columns>
        </c1:C1FlexGrid>
    </Grid>
</Window>



MainWindow.xaml.cs


using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using C1.WPF.FlexGrid;

namespace FlexGridMergeManagerSampleForWPF
{
    /// <summary>
    ///     Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private const string CASE1 = "Using grid[r,c]";
        private const string CASE2 = "Using CollectionView";

        public MainWindow()
        {
            InitializeComponent();
        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            var button = (Button) sender;
            switch (button.Content.ToString())
            {
                case CASE1:
                    BindGrid(CASE1);
                    break;
                case CASE2:
                    BindGrid(CASE2);
                    break;
            }
        }

        private void BindGrid(string type)
        {
            FlexGrid.MergeManager = new SampleMergeManager(type);

            var allText = File.ReadAllText("sample.csv");
            if (string.IsNullOrEmpty(allText)) return;
            var lines = allText.Split('\n');

            var items = (from line in lines.Skip(1)
                where string.IsNullOrEmpty(line) == false
                let columns = line.Split(',')
                select new SampleModel
                {
                    OrderID = Convert.ToInt32(columns[0]),
                    ProductID = Convert.ToInt32(columns[1]),
                    ProductName = columns[2],
                    UnitPrice = Convert.ToDouble(columns[3]),
                    Quantity = Convert.ToInt32(columns[4]),
                    Discount = Convert.ToDouble(columns[5]),
                    ExtendedPrice = Convert.ToDouble(columns[6].Replace("\r", ""))
                }).ToList();

            // bind grids to ListCollectionView
            FlexGrid.ItemsSource = items;
        }

        private class SampleMergeManager : IMergeManager
        {
            private static long _count;
            private readonly string _getDataType;

            public SampleMergeManager(string type)
            {
                _getDataType = type;
            }

            public CellRange GetMergedRange(C1FlexGrid grid, CellType cellType, CellRange rng)
            {
                if (cellType != CellType.Cell) return rng;
                var col = grid.Columns[rng.Column];
                if (col.AllowMerging == false) return rng;

                for (var i = rng.Row; i < grid.Rows.Count - 1; i++)
                {
                    if (CompareNext(grid, i, rng.Column))
                        break;
                    rng.Row2 = i + 1;
                }

                for (var i = rng.Row; i > 0; i--)
                {
                    if (ComparePrev(grid, i, rng.Column))
                        break;
                    rng.Row = i - 1;
                }

                _count++;
                Debug.WriteLine($"count : {_count}");
                return rng;
            }

            private bool CompareNext(C1FlexGrid grid, int r, int c)
            {
                if (_getDataType == CASE1)
                    return grid[r, c]?.ToString() != grid[r + 1, c]?.ToString();

                var col = grid.Columns[c];
                if (!(grid.CollectionView is ListCollectionView collection)) return false;
                var item1 = collection.GetItemAt(r);
                var item2 = collection.GetItemAt(r + 1);

                var property = item1.GetType().GetProperty(col.Binding.Path.Path);
                if (property == null) return false;
                var val1 = property.GetValue(item1);
                var val2 = property.GetValue(item2);

                return val1?.ToString() != val2?.ToString();
            }

            private bool ComparePrev(C1FlexGrid grid, int r, int c)
            {
                if (_getDataType == CASE1)
                    return grid[r, c]?.ToString() != grid[r - 1, c]?.ToString();

                var col = grid.Columns[c];
                if (!(grid.CollectionView is ListCollectionView collection)) return false;
                var item1 = collection.GetItemAt(r);
                var item2 = collection.GetItemAt(r - 1);

                var property = item1.GetType().GetProperty(col.Binding.Path.Path);
                if (property == null) return false;
                var val1 = property.GetValue(item1);
                var val2 = property.GetValue(item2);

                return val1?.ToString() != val2?.ToString();
            }

        }
    }
}


소스

https://github.com/kaki104/BasicSamples/tree/master/FlexGridMergeManagerSampleForWPF


반응형
댓글