15/09/2009

GridView oraz puste źródło danych

Home

Programistom używającym kontrolki GridView na co dzień znany jest zapewne fakt, że w przypadku pustego źródła danych kontrolka nie generuje żadnego widocznego markup'u. W szczególności nie będą widoczne nagłówki kolumn czy wiersz dodający.

Kiedy w wyszukiwarce wpiszemy hasło Show GridView if datasource is empty otrzymamy oczywiście mnóstwo rozwiązań tego problemu. Niestety pośród nich nie znajdziemy, a przynajmniej ja nie znalazłem, satysfakcjonującej odpowiedzi dotyczącej źródła danych typu ObjectDataSource. Nie będziemy natomiast osamotnienie jeśli używamy SqlDataSource. Ale co jeśli nie chcemy, nie możemy lub najzwyczajniej w świecie nie chce nam się zmieniać używanego typu źródła danych. Ja zastosowałem rozwiązanie, które opisałem poniżej.

Dla ustalenia uwagi załóżmy, że metoda dostarczająca danych wygląda następująco:
public static IEnumerable GetData()
{
  return _data;
}
Zacznijmy od zmodyfikowania tej metody w ten sposób aby zawsze zwróciła niepustą kolekcję:
public static IEnumerable GetData()
{
  if(_data.Count == 0)
  {
    _data.Add(new TestClass());
  }
  
  return _data;
}
Oczywiście teraz wszystko zadziała z wyjątkiem tego, że na kontrolce pojawi się jakiś "dziwny", sztuczny obiekt. Można temu jednak zaradzić zmieniając lekko definicję TestClass:
public class TestClass
{
  ...
  public bool IsFake
  {
    get; set;
  }
  ...
}
Przy okazji zmodyfikujemy ponownie metodę GetData:
public static IEnumerable GetData()
{
  if(_data.Count == 0)
  {
    _data.Add(new TestClass() { IsFake = true; });
  }
  
  return _data;
}
Ostatni element rozwiązania do podczepienie się pod zdarzenie OnRowDataBound kontrolki GridView w celu sterowania widocznością wierszy:
protected void GridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
  TestClass ts = e.Row.DataItem as TestClass;
  if(ts != null && ts.IsFake)
  {
    e.Row.Visible = false;
  }
}
Rozwiązanie można jeszcze rozszerzyć o usunięcie sztucznego obiektu z kolekcji w momencie kiedy pojawią się "prawdziwe" dane ale moim zdaniem nie jest to konieczne.

04/09/2009

Trochę na temat oferty ESRI

Home

Tak jak obiecałem w ostatnim poście teraz poświęcę trochę czasu na omówienie oferty firmy ESRI, która dla kogoś nie związanego na co dzień z GIS'ami może wydać się niezrozumiała i zagmatwana i taka mówiąc szczerze jest. Sądzę, że takie zestawienie może być ciekawe i przydatne dla kogoś stawiającego pierwsze kroki w świecie geograficznych systemów informacyjnych (wiem to z własnego doświadczenie) i nie tylko. A więc zaczynamy.

Po pierwsze wyróżnijmy dwie kategorie produktów. W pierwszej umieścimy gotowe, pudełkowo aplikacje, a w drugiej rozwiązania przeznaczone dla programistów. W pierwszej znajdziemy:
  • ArcGIS Desktop. Flagowa aplikacja, a raczej zestaw aplikacji ESRI pozwalających na przeglądanie i analizowanie zgromadzonych danych geograficznych, zarządzanie nimi, edytowanie, tworzenie i tysiące innych rzeczy. Najważniejsze składowe pakietu ArcGIS Desktop to aplikacja administracyjna ArcCatalog, właściwa aplikacja do oglądania i przetwarzania danych czyli ArcMap oraz ArcGlobe służąca do pracy z danymi trójwymiarowymi. W obecnej chwili ArcGIS Desktop dostępne jest w trzech wersjach różniących się między sobą zakresem funkcjonalności. Są to odpowiednio: ArcView, ArcEditor oraz ArcInfo.


  • ArcView. To nie tylko nazwa jednej z wersji ArcGIS Desktop ale również nazwa starej aplikacji będącej w prostej linii jej poprzedniczką.


  • ArcGIS Server. Dedykowany do zastosowań GIS'owych serwer aplikacyjny. Dostarcza bogaty zestaw usług webowych takich jak: geokodowanie, lokalizowanie... oraz umożliwia tworzenie własnych. Pozwala na publikowania w sieci danych geograficznych oraz zawiera kilka platform do tworzenia mapowych aplikacji WWW i mobilnych. ArcGIS Server sprzedawany jest w wersjach: Basic, Standard oraz Enterprise. ESRI stworzyła również zestaw specjalizowanych rozszerzeń dla serwera np.: do analiz i modelowania 3D.


  • ArcPad. Dedykowana dla urządzeń mobilnych aplikacja o dużych możliwościach konfiguracyjnych pozwalających na dostosowanie do konkretnych potrzeb. Również aplikacja wykonująca synchronizację pomiędzy urządzeniem mobilnych, a centralną bazą danych.


  • ArcSDE. Nakładka na relacyjną bazę danych, uruchamiana jako usługa, umożliwiająca przechowywanie w niej danych przestrzennych.


  • ArcGIS Explorer. Prosty klient dla ArcGIS Server umożliwiający przeglądanie danych geograficznych dostępnych w sieci, na przykład w serwisie ArcGIS Online. Ta aplikacja jest w całości darmowa.


  • ArcReader. Aplikacja o podobnej funckjonalności co ArcGIS Explorer ale służąca do przeglądania danych przestrzennych stworzonych w ArcGIS Desktop i opublikowanych przy pomocy aplikacji ArcPublisher. Również darmowa.


  • ArcIMS. W pewnym uproszczeniu poprzednik ArcGIS Server. ESRI zaleca użycie następcy.


  • ArcGIS for AutoCAD. Darmowe narzędzia zapewniające interoperacyjność pomiędzy rozwiązaniami ESRI i AutoCAD.


  • ArcPublisher. Rozszerzenie ArcGIS Desktop o możliwość publikowania map w sieci.
Ofertę dla developerów tworzą natomiast:
  • MapObjects. Stare API programistyczne umożliwiające tworzenie okienkowych aplikacji mapowych. Technologia używana coraz rzadziej.


  • ArcObjects. Zestaw komponentów COM w oparciu, o które zostały stworzone prawie wszystkie produkty z oferty ESRI: ArcGIS Desktop
  • , ArcGIS Server, ArcGIS Engine itd.

  • ArcGIS Engine. Platforma programistyczna (COM, .NET, Java i C++) oparta o ArcObjects służąca tworzeniu aplikacji okienkowych oraz do dostosowywania aplikacji z pakietu ArcGIS Desktop do swoich potrzeb.


  • ArcGIS Mobile. Platforma programistyczna (C#, Java) do tworzenia aplikacji mobilnych sprzedawana razem z ArcGIS Server w wersji Enterprise.


  • Web ADF (Application Development Framework). Platforma programistyczna do tworzenia aplikacji WWW sprzedawana razem z ArcGIS Server w wersji Standard. Dostępna dla .NET i Java . W przypadku .NET oparta oczywiście o ASP.NET Ajax.


  • ArcGIS Web Mapping APIs. Zestaw interfejsów programistycznych/bibliotek do tworzenia aplikacji mapowych w WPF/Silverlight, JavaScript i Flex darmowych do niekomercyjnego użytku. W porównaniu do Web ADF ma bardzo ograniczone możliwości.
Przegląd ten pomimo, że dość długi nie jest kompletny. Zawiera jednak większość, a z pewnością najważniejsze z produktów z oferty firmy ESRI. Można również spierać się co do użytego przeze mnie podziału. Z mojego doświadczenie wynika jednak, że z tej gromady Arc'ów może być trudno wyłowić to co jest przydatne dla programisty.

03/09/2009

ESRI WPF/Silverlight API

Home

ESRI to lider światowego rynku systemów informacji geograficznej (ang. GIS). Lider przez duże L - Na całym świecie z rozwiązań ESRI korzysta 300 tyś instytucji w tym 2/3 firm z listy Fortune. ESRI to taki Microsoft w świecie GIS'ów :). Czym jednak są systemy GIS'owe?

GIS to w bardzo dużym skrócie system służący do wprowadzania, przechowywania, przetwarzania, analizowania i wizualizowania danych przestrzennych. Upraszczając jeszcze bardziej, a wręcz trywializując chodzi tu po prostu o mapę ;) Niektórzy zapewne pomyślą coś w rodzaju: "Czym ty zawracasz głowę człowieku, przecież jest już Google Maps". Nie obrażając nikogo Google Maps w porównaniu z produktami ESRI to zabawka dla dzieci, którą poważni ludzie się nie zajmują. Patrząc na to z innej strony oferta ESRI (w jednym z kolejnych postów postaram się ją przybliżyć) jest dużo, dużo, dużo bogatsza. Poza tym jest skierowana do zupełnie innego rodzaju odbiorców, którzy poza wizualizacją danych geograficznych chcą je analizować i przetwarzać w celu usprawnienia swoich procesów biznesowych.

Czemu jednak w ogóle o tym piszę? Otóż rozwiązania ESRI są generalnie bardzo drogie i dostępnie dla niewielkiego grona specjalistów, a co z tym związane mało znane. Ostatnio dotarłem jednak do darmowego (dla celów niekomercyjnych) API dla WPF/Silverlight umożliwiającego tworzenie całkiem fajnych aplikacji. Tworzone aplikacje możemy zasilić danymi udostępnianymi przez ESRI poprzez ArcGIS Online. Zasoby udostępnione publicznie nie są tak duże jak w przypadku Google ale można już coś zdziałać przy ich pomocy. Możliwe jest również wykorzystanie map publikowanych przez Microsoft na Bing Maps.

Potrzebne biblioteki można pobrać tutaj, a dokumentację znajdziemy tutaj. Początkowo chciałem opisać prosty przykład użycia ale zrezygnowałem z tego kiedy zobaczyłem tą stronę. Znajdziecie tam kilkanaście bardzo prostych, poglądowych aplikacji. Polecam.

26/08/2009

Przykład tego jak nie należy pisać kodu

Home

Czasami jak patrzę na niektóre kody to zastanawiam się o czym myślał piszący je programista. Ostatnio natknąłem się na kod mniej więcej jak poniżej (zmieniłem nazwy zmiennych, metod itd.). Pomińmy jaka jest jego logika i gdzie został użyty. Proponuję natomiast przyjrzeć się przez chwilę temu fragmentowi i spróbować odpowiedzieć na pytanie co jest nie tak.
...
for (int i = 0; i < values.Length; i++)
{
  if (values[i] != null)
  {
    if (hash[values[i]] != null)
      Process(hash[values[i]]);

    if (hash[values[i]] != null)
    { 
      Process(values[i]);
      Process(values[i], hash[values[i]]);
      hash.Remove(values[i]);
    }
  }
}
...
Mnie uderzyła duża i zupełnie zbyteczna liczba odwołań do zmiennych values (tablica) i hash (Hashtable). Odwołanie do tej pierwszej występuje 8 razy, a do drugiej 5 razy! Po chwili pracy i wprowadzeniu bardzo prostych poprawek kod wygląda tak:
...
for (int i = 0; i < values.Length; i++)
{
  string val = values[i];
  if (val != null)
  {
    object obj = hash[val];
    if (obj != null)
      Process(obj);

    if (obj != null)
    {
      Process(val);
      Process(val, obj);
      hash.Remove(obj);
    }
  }
}
...
Odwołanie do zmiennych values oraz hash występuje tylko 1 raz. Czemu o tym piszę? Odpowiedź jest tak prosta jak wprowadzone poprawki: wydajność. Dodam jescze, że kod ten można jeszcze ulepszyć. W tym poście skupiam się jednak na tej jednej rzeczy.

W tym przypadku poprawiona wersja działa jakieś 3x/4x razy szybciej! Przyznam jednak, że całościowy efekt tej optymalizacji jest niezauważalny z dwóch powodów. Po pierwsze długość używanej w kodzie tablicy i liczba elementów w tablicy hashującej jest generalnie niewielka. Przeważnie nie przekracza kilkudziesięciu, może kilkuset elementów. W takim scenariuszu czas wykonania tego kodu nie przekracza milisekundy. Po drugi częstotliwość użycia tego kodu jest niewielka.

Z drugiej jednak strony programista, który napisał omawiany kod stosuje (zastosował) takie konstrukcje w wielu miejscach. Być może wywołuje jedną, ciężką, metodę wielokrotnie zamiast zapamiętać jej wynik wywołania na później. Przykładów takich można mnożyć.

Reasumując należy uczyć się na cudzych błędach i strzec się takich konstrukcji.

18/08/2009

Ciekawy przypadek optymalizacji

Home

Ostatnio zajmowałem się optymalizacją aplikacji mapowej do planowania i inwentaryzacji sieci telekomunikacyjnych. Problem polegał na tym, że przy dużej liczbie warstw aplikacja zaczynała działać powoli. Warstwa to taki pojemnik na dane tego samego rodzaju np.: warstwa kabli, warstwa wzmacniaczy itd.

W określonych scenariuszach liczba takich warstw mogła sięgać nawet kilku tysięcy. Zacząłem od wrzucenia aplikacji do profilera (AQTime). Jak to często bywa w takich sytuacjach okazało się, że czas pożera kilka metod, które same z siebie wykonują się bardzo szybko ale są wołane bardzo dużo razy - proporcjonalnie do liczby rastrów. W rzeczywistości dojście to tego o jakie metody chodzi nie było oczywiście takie proste ale nie będę zanudzał szczegółami.

Po pierwsze postanowiłem ograniczyć liczbę wywołań tych metod. Niestety okazało się, że z różnych powodów nie da się tego zrobić. W drugim podejściu postanowiłem, więc ograniczyć czas potrzebny na ich wykonanie. Co ciekawe okazało się, że metody te pozornie prawie nic nie robią czyli zawierają tylko odwołania do właściwości Count czy też indeksera jakiejś kolekcji.

Zanim przejdę dalej wyjaśnię, że jako platformę mapową używam rozwiązań firmy ESRI opartych o technologię COM. W związku z tym konieczne jest użycie mechanizmów interoperacyjności pomiędzy kodem zarządzanym i niezarządzanym. W omawianym przypadku wspomniana kolekcja nie była kolekcją zarządzaną ale wrapper'em na obiekt COM. Postanowiłem, więc zrezygnować z odwołań do tej kolekcji i użyć dobrze znanej klasy List<T>. W praktyce utworzyłem instancję listy zarządzanej istniejącą równolegle do kolekcji niezarządzanej. Elementy do obu kolekcji dodawane są równocześnie, podobnie usuwane. Nie jest to problem ponieważ czynność ta wykonywana jest jednorazowo.

Postępując podobnie w kilku innych miejscach, to znaczy eliminując odwołania do wrapper'ów do obiektów COM, zmniejszyłem czas wykonywania niektórych czynności o połowę! Wydaje mi się, że to niezły wynik szczególnie, że dalsze optymalizację cały czas są możliwe. Wniosek z tego taki, że czasem warto wprowadzić redundancję aby zyskać na wydajności.