Załóżmy, że mamy zadanie: posortować macierz na pierwszej stronie w odpowiedniej kolejności. Możesz również potrzebować zapamiętać tę kolejność i użyć jej do sortowania podobnych macierzy na innych stronach.
Może się to przydać, gdy masz kilka stron w raporcie, które mają ten sam nagłówek macierzy, ale tylko dane są różne. Na przykład, pierwsza macierz podaje liczbę sprzedanych pozycji, a druga kwotę sprzedaży w podziale na pozycje. Musisz posortować według ilości lub kwoty, a następnie zastosować tę samą kolejność do drugiej macierzy. Ten przypadek jest dość powszechny w raportach analitycznych.
Przyjrzyjmy się temu w praktyce. Weźmy zupełnie hipotetyczną statystykę sprzedaży owoców. Nie wystarczą jednak same rodzaje owoców, niech to będzie lista krajów importujących owoce Liczba sprzedanych produktów będzie obliczana w okresie trzech lat.
Konstrukcja tabeli:
- country_name
- fruit_type
- year
- amount
- price
- sum
Sortowanie
Standardowe mechanizmy sortowania nie ułatwią nam tego zadania. Zaimplementujmy więc sortowanie liczby sprzedanych owoców dla każdego kraju. Załóżmy, że mamy sekwencję kroków:
1. Uzyskanie listy krajów.
2. Dla każdego kraju:
2.1 uzyskać wartości komórek z rodzajami owoców i ilościami sprzedanymi dla każdego roku;
2.2. sortuj wartości dla wybranego roku;
2.3. dla każdego wiersza zapisać komórki rodzaju i ilości owoców dla wszystkich lat zgodnie z indeksami wierszy na posortowanej liście.
Sortowanie pierwszej kolumny to kraje, co nas satysfakcjonuje, więc posortujemy komórki pozostałych kolumn. Dlatego musimy je wcześniej zapamiętać, aby móc je ułożyć w odpowiedniej kolejności, zgodnie z naszym planem sortowania. Wybierzemy jedną z kolumn z danymi dla danego roku i posortujemy ją w kolejności malejącej lub rosnącej. Następnie użyj kolejności indeksu, aby posortować wszystkie komórki w kolumny.
Zaczynamy. Matryca posiada specjalne zdarzenie do modyfikacji obiektu, który został już zbudowany - ModifyResult. Utwórzmy handler dla tego zdarzenia w skrypcie raportu.
private List<List<int>> sortOrders = new List<List<int>>(); //Lista kolejności sortowania dla każdego gatunku owoców z podziałem na kraje private void Matrix1_ModifyResult(object sender, EventArgs e) { //Słowniki, w których będziemy przechowywać indeks łańcucha i wartość komórki Dictionary<int, double> firstYearCells = new Dictionary<int, double>(); Dictionary<int, double> secondYearCells = new Dictionary<int, double>(); Dictionary<int, double> thirdYearCells = new Dictionary<int, double>(); Dictionary<int, string> typeCells = new Dictionary<int, string>(); Dictionary<int, double> sortCells = new Dictionary<int, double>(); //bool prevYearSortNeeded = false; var total = false; var z = 1; var val2 = 0.0; var val3 = 0.0; List<string> countries = new List<string>(); // W tej liście będziemy przechowywać listę krajów //Wyświetl wszystkie kraje z pierwszej kolumny for (int j=2; j<(sender as TableBase).ResultTable.RowCount-1; j++) { try { var val = (sender as TableBase).ResultTable.GetCellData(0,j).Value.ToString(); if (val.Length > 0) countries.Add(val); } catch (Exception) {} } int columnFirstYearIndex=0; int columnSecondYearIndex=0; int columnThirdYearIndex=0; int columnTypeIndex=0; //Przejdź przez wszystkie kolumny matrycy, aby zapisać komórki do słowników for (int t=0; t < (sender as TableBase).ResultTable.ColumnCount; t++) { if ((sender as TableBase).ResultTable.GetCellData(t,0).Text.Contains("2017")) { columnFirstYearIndex=t; } if ((sender as TableBase).ResultTable.GetCellData(t,0).Text.Contains("2018")) { columnSecondYearIndex=t; } if ((sender as TableBase).ResultTable.GetCellData(t,0).Text.Contains("2019")) { columnThirdYearIndex=t; } if ((sender as TableBase).ResultTable.GetCellData(t,0).Text.Contains("Fruit")) { columnTypeIndex=t; } } int countryOrder =0; //Dla każdego kraju zastosuj serie, aby zidentyfikować grupy owoców i posortować je. foreach (var country in countries) { total = false; sortCells.Clear(); // Wyczyść listę do sortowania // Wybierz komórki w wierszach, aż do momentu, gdy osiągniesz wartość Total. Ponieważ Total nie powinien być sortowany while (!total) { if ((string)(sender as TableBase).ResultTable.GetCellData(columnTypeIndex,z).Text!="Total") { //Wybierz komórki dla pierwszego roku var value = (sender as TableBase).ResultTable.GetCellData(columnFirstYearIndex,z).Value; if (value!=null) { Double.TryParse(value.ToString(),out val3); firstYearCells.Add(z,val3); } else firstYearCells.Add(z, 0.0); //Wybierz komórki dla drugiego roku value = (sender as TableBase).ResultTable.GetCellData(columnSecondYearIndex,z).Value; if (value!=null) { Double.TryParse(value.ToString(),out val3); secondYearCells.Add(z,val3); } else secondYearCells.Add(z, 0.0); //Wybierz komórki dla trzeciego roku value = (sender as TableBase).ResultTable.GetCellData(columnThirdYearIndex,z).Value; if (value!=null) { Double.TryParse(value.ToString(),out val3); thirdYearCells.Add(z,val3); } else thirdYearCells.Add(z, 0.0); //Określanie pól dla rodzajów owoców value = (sender as TableBase).ResultTable.GetCellData(columnTypeIndex,z).Text; typeCells.Add(z,value.ToString()); } else { //Warunek zakończenia serii. total = true; } z++; } sortCells = firstYearCells; //Określ kolumnę, która ma być posortowana - w tym przypadku dla pierwszego roku List<int> keys = new List<int>(); //Jeśli mamy kompletną listę sortowania dla wszystkich krajów, //to pierwsza strona raportu jest zbudowana i możemy użyć tej listy na drugiej stronie. //To właśnie na tym etapie zapewnione jest sortowanie end-to-end. if ( sortOrders.Count == countries.Count ) { keys = sortOrders.ElementAt(countryOrder); } else keys = sortCells.OrderByDescending(i=>i.Value).Select(key => key.Key).ToList(); //Posortuj tablicę w malejącej kolejności używając biblioteki Linq int k = 0; //Przejdź przez wszystkie elementy posortowanej listy foreach(var key in keys) { //Uporządkuj wartości komórek dla wszystkich kolumn w kolejności sortowania (sender as TableBase).ResultTable.GetCellData(columnFirstYearIndex, firstYearCells.Keys.ElementAt(k)).Text = firstYearCells[key].ToString(); (sender as TableBase).ResultTable.GetCellData(columnSecondYearIndex, secondYearCells.Keys.ElementAt(k)).Text = secondYearCells[key].ToString(); (sender as TableBase).ResultTable.GetCellData(columnThirdYearIndex, thirdYearCells.Keys.ElementAt(k)).Text = thirdYearCells[key].ToString(); (sender as TableBase).ResultTable.GetCellData(columnTypeIndex, typeCells.Keys.ElementAt(k)).Text = typeCells[key].ToString(); k++; } if (keys.Count>0) sortOrders.Add(new List<int>(keys)); //Zapisz kolejność sortowania dla bieżącego kraju //Ważne jest, aby wyczyścić firstYearCells.Clear(); secondYearCells.Clear(); thirdYearCells.Clear(); typeCells.Clear(); countryOrder++; //Przejdź do następnego kraju } } }
Teraz kopiujemy stronę raportu z matrycą, ale zamiast pola amount wyświetlimy sumę.
I w zdarzeniach matrycy wybierz handler, który utworzyliśmy dla ModifyResult.
W wyniku uruchomienia raportu zobaczymy, że kolejność typów owoców na obu stronach jest taka sama. Oznacza to, że sortowanie uzyskane na pierwszej stronie zostało zastosowane również na drugiej stronie.
W ten sposób możemy wykorzystać skrypt raportu do dowolnego zarządzania danymi w matrycy. I co najważniejsze, możemy zastosować tę samą kolejność sortowania na różnych stronach raportu.