Archive for the ‘.NET CF’ Category

Emulator & WM 6.1

kwiecień 6, 2008

Microsoft udostępnił obraz systemu Windows Mobile 6.1 dla emulatorów. Jak na razie dostępna jest tylko wersja anglojęzyczna. Pliki do pobrania znajdują się tutaj.

OAC - Orientation Aware Control

styczeń 30, 2008

Stworzenie przejrzystego i funkcjonalnego interfejsu dla aplikacji mobilnej nie jest prostym zadaniem. Szczególnie obecnie gdy dynamika rynku urządzeń mobilnych cały czas się zwiększa i co rusz spotykamy się z nowymi rodzajami wyświetlaczy. Projektując interfejs aplikacji mobilnej musimy mieć na uwadze trzy parametry wyświetlania: rozdzielczość, rozmiar ekranu, i tryb wyświetlania. Rozdzielczość określana jest w DPI (ang. dot per inch) im większa tym więcej możemy zmieścić na ekranie. Typowymi rozdzielczościami są QVGA (Quater - VGA) która wynosi 96 DPI i VGA wynosząca 192 DPI. Rozmiar ekranu, podawany jest w pikselach i typowo wynosi 240×320 (szerokość/wysokość). Tryb wyświetlania określa czy nasze okno wyświetlane jest pionowo (vertical/portrait) bądź poziomo (horizontal/landscape).

Rozdzielczością, automatycznie zajmuje się Visual Studio, po za tymi sporadycznymi przypadkami gdy ręcznie tworzymy kontrolki. Musimy wtedy rozmiary komponentu przemnożyć przez, że tak to nazwę, współczynnik skalujący - dostosowujący wymiary do aktualnej rozdzielczości. Skalę możemy określić na przykład tak:


static class Program
{

[MTAThread]
static void Main()
{
  frmScaling f = new frmScaling();

  // rozdzielczość dla której projektowaliśmy aplikację
  const float designResolution = 96.0f;
  System.Drawing.Graphics g = f.CreateGraphics();
  float runningResolution = g.DpiX;

  ScaleFactor = runningResolution / designResoluion;
  g.Dispose();

  Application.Run(f);
}

  // Przemnóż wszystkie ‘ręcznie’ tworzone kontrolki przez
  // Program.ScaleFactor,
  // Przez większość czasu będą one przyjmowały jedną z
  // trzech wartości:
  // 1 - gdy zaprojektowaliśmy aplikację dla rozdzielczości
  //     na której pracujemy
  // 2 - gdy zaprojektowaliśmy aplikację dla 96dpi ale
  //     pracujemy na 192 dpi
  // 1.365 - gdy zaprojektowaliśmy aplikację dla 96dpi ale
  //     pracujemy na 131dpi (QVGA Smartphone)
  internal static float ScaleFactor;
}

Więcej na ten temat można znaleźć w książce Microsoft Mobile Development Handbook na strony 63 - 66.

Niestety wymiarami ekranów i trybem pracy musimy zająć się sami. Jest kilka sposobów aby ułatwić sobie, życie. Jednym z nich jest projektowanie interfejsu z myślą o kwadratowym ekranie. Mato swoje zalety - interfejs zawsze będzie taki sam niezależnie czy aplikacja pracuje w trybie pionowym czy poziomym. Wadą tego rozwiązania jest to, że na ekranach prostokątnych, marnujemy całkiem sporą ilość wolnej przestrzeni. Myślę, że można wziąć to rozwiązanie pod uwagę dla prostych aplikacji bez wyszukanego interfejsu użytkownika.

Innym rozwiązaniem jest stworzenie osobnych kontrolek - reprezentujących zawartość danego okna - i dynamicznej ich zamianie w zależności od wymaganego położenia. Rozwiązanie to wymaga jednak większego nakładu pracy gdyż nie dość, że musimy zaprojektować dwa różne ekrany i obsłużyć zdarzenie zmiany położenia ekranu. Prosty przykład tego rozwiązania można znaleźć w jednym z wcześniejszych moich postów. Przykład ten prezentuje dodatkowo jak wykorzystać wzorzec MVP (Model-View-Presenter) aby nie duplikować kodu wewnątrz kontrolek.

Kolejnym rozwiązaniem, obecnie chyba najłatwiejszym, jest skorzystanie w Orientation Aware Control w skrócie OAC. OAC jest kontrolką kontenerem i odpowiada funkcjonalności standardowej UserControl. Jednak posiada szereg nowych właściwości dzięki którym, możemy, na tylko jednej (!) kontrolce zaprojektować layout’y dla różnych trybów pracy ekranu. Czyli w sumie cała ciężka praca jest zrobiona za nas - jedyne co nam pozostaje to rozplanować prawidłowe położenie kontrolek.

Komponent OAC możemy pobrać z dwóch źródeł. Pierwszym jest pakiet Microsoft Patterns & Practises - Mobile Client Software Factory (MCSF). Niestety został on wydany prawie dwa lata temu (lipiec 2006) i od tego czasu nie był uaktualniany. Drugim źródłem jest strona www.orientationaware.net - tutaj możemy znaleźć najnowszą wersję tejże kontrolki, niestety jest już to kontrolka komercyjna. Fakt na stronie jest udostępniona wersja Community Edition ale jest ona dość poważnie ograniczona tzn. obsługuje tylko jedną rozdzielczość (QVGA).

Z moich doświadczeń wynika, że wersja kontrolki dostarczona MCSF w zupełności wystarcza i nie powoduje większych problemów. Jednakże trzeba mieć na uwadze, że w przypadku jakichkolwiek kłopotów, możemy mieć problem z otrzymaniem pomocy (ostatnie tematy z forum są datowane na rok 2006), i albo kupimy komercyjną wersję kontrolki, albo sami będziemy musieli zgłębić jej kod źródłowy.

Jak to wszystko działa? Otóż, przede wszystkim musimy dodać referencje do assembly:
Microsoft.Practices.Mobile.UI.OrientationAware.dll
i
Microsoft.WindowsMobile.Status.dll
lub tylko
Clarius.UI.OrientationAware.dll
w przypadku wersji komercyjnej. Kolejnym krokiem będzie utworzenie nowej UserControl i zmianie klasy z której ona dziedziczy na OrientationAwareControl.

 

Teraz możemy otworzyć naszą kontrolkę w designerze, właściwościami na które powinniśmy zwrócić uwagę to Orientation i Resolution. Jak nazwy wskazują Orientation określa jak nasze okno jest położone (vertical/horizontal) a Resolution pozwala nam wybrać rozdzielczość dla jakiej projektujemy nasz interfejs. Kontrolka dostarczona nam przez MS Pattern & Practises pozwala nam na wybór pomiędzy: 240×320 (QVGA), 480×640 (VGA), 240×240 (kwadratowa QVGA), 480×480 (kwadratowa VGA) co w większości przypadków jest wystarczające. Kontrolka dostarczona nam przez Clarius Consulting (www.orientationaware.net) - rozszerza ten zakres i pozwala na definiowanie własnych rozmiarów. Następnie na powierzchni naszej kontrolki umieszczamy resztę elementów, np.:

Gdy jesteśmy zadowoleni z wyglądu kontrolki pora utworzyć interfejs dla trybu landscape. W tym celu możemy zmienić właściwość Orientation z okna Properties bądź skorzystać z menu kontekstowego kontrolki i wybrać ‘Rotate‘. Teraz nie pozostaje nam nic innego jak dostosować wielkość kontrolki i odpowiednio rozmieścić elementy na niej.

Nie jesteśmy bynajmniej ograniczeni tylko do zmiany położenia elementów naszej kontrolki - możemy również zmieniać pozostałe właściwości jak np. ich rozmiary, właściwość Text czy Image. Ograniczeniem z jakim się spotykamy jest niemożliwość dodawania nowych elementów na widokach innych niż domyślny. Jeśli chcemy aby jakaś kontrolka była widoczna tylko w trybie landscape - musimy najpierw przejść do widoku domyślnego domyślnego, tzn. nie tylko położenia horizontal ale także domyślnej rozdzielczości, możemy tego dokonać poprzez wybranie opcji z menu kontekstowego kontrolki ‘Switch to Default Layout‘. Teraz dodajemy nową kontrolkę i ustawiamy jej właściwość Visible na false i zmieniamy ją w kodzie w momencie wykrycia zmiany orientacji ekranu. Właściwości Orientation Aware Control, dla wszystkich trybów wyświetlania, oprócz domyślnego są przechowywane jako zasoby. Dlatego też, jeśli przyjrzymy się pozycji Resources naszej kontrolki zobaczymy coś takiego:

Pojedynczy plik określa właściwości jednego trybu wyświetlania i aby zmniejszyć rozmiar zasobów przechowuje tylko wartości które uległy zmianie z widoku domyślnego.

Problem jaki wiąże się z przechowywaniem właściwości w zewnętrznych zasobach jest to, że są one odczytywane przy każdej zmianie widoku i nie zachowują aktualnego stanu poszczególnych kontrolek. Weźmy na przykład aplikację korzystającą z OAC w którym znajduje się kontrolka TextBox, użytkownik wpisuje do niego dane i zmienia orientację ekranu - w tym momencie właściwości kontrolki OAC są odczytywane z zasobów i zawartość naszej kontrolki zostaje zastąpiona domyślną wartością. Dlatego też musimy sami zadbać o przechowywanie zawartości elementów naszej OAC.

Na koniec kilka szczegółów o których powinniśmy wiedzieć:

  • Forma na której zamierzamy umieścić naszą kontrolkę pochodzącą od OAC powinna mieć ustawioną właściwość AutoScaleMode na None, gdyż skalowanie odbywa się trakcie projektowania i prawidłowe rozmiary są zapisane w zasobach.
  • Gdy projektujemy interfejs dla trybu VGA, wszystkie kontrolki są dwa razy większe niż zazwyczaj. Nie jest to błąd - Visual Studio 2005 (i zapewne VS 2008 też, ale nie testowałem tego) odwzorowuje kontrolki w ich rzeczywistych rozmiarach a ponieważ VGA jest dwa razy lepsza od QVGA na ekranach naszych monitorów otrzymujemy nieco większe niż przywykliśmy. Niestety taka jest specyfika Visual Studio i nie jesteśmy wstanie nic z tym zrobić.

Dodatkowych informacji można szukać na stronach Clarius Consulting bądź w udostępnionym przez Microsoft webcast’cie ‘Designing Zero-Code Adaptive UIs Using the Orientation Aware Control’. Źródła przykładowej aplikacji jest dostępne na tutaj.

Nowe ‘mobilne’ screencast’y

styczeń 24, 2008

Kompatybilność i SQL Server Compact Edition

styczeń 10, 2008

Na blogu SQL Server Compact Team Blog pojawił się artykuł omawiający wzajemną kompatybilność poszczególnych wersji SQL Server Compact Edition. I tak np. można się dowiedzieć, że np. designer z Visual Studio 2008 będzie pracował tylko z wersją 3.5, co jest nieco zaskakujące bo po produkcie takim jak Visual Studio można by się spodziewać nieco lepszej kompatybilności wstecznej.

.NET Compact Framework 3.5 Redistributable

styczeń 8, 2008

Microsoft udostępnił wersję redistributable .NET Compact Framework 3.5 - do pobrania tutaj.

.NET Compact Framework 3.5 Power Toys

grudzień 12, 2007

Pojawiła się kolejna wersja zbioru power toys‘ów dla .NET Compact Framework‘u wersji 3.5 - numerek wersji trzeba podkreślić, gdyż jest on bardzo ważny, o czym za chwilę. W skład pakietu wchodzą:

  • Remote Performance Monitor and GC Heap Viewer - super narzędzie umożliwiające nam dostęp do wszelakiej maści liczników pozwalających określić wydajność naszej aplikacji. Dodatkowo mamy możliwość podejrzenie stosu Garbage Collectora (GC) i zapisania jego stanu w celu późniejszej analizy, świetnie nadaje się to do poszukiwania ‘wycieków pamięci’. Wcześniejsze wersje tego narzędzia nie umożliwiały pracy z emulatorem, w tym wydaniu ograniczenie to zostało zniesione i nie musimy posiadać fizycznego urządzenia do przeprowadzenia testów. Zastanawia mnie jednak, jak testy na emulatorze mają się do testów na rzeczywistym PDA, wydaje mi się, że nie powinno być jakiś strasznych rozbieżności. Na pewno wystarczy do wyrobienia sobie poglądu jak nasza aplikacja się sprawuje.
  • NETCF CLR Profiler (NetCFCLRProfiler.exe)- to jest dopiero narzędzie, potrafi przedstawić graficzną reprezentację następujących po sobie alokacji i de-alokacji pamięci, kolejność wywołań funkcji itp.
  • App Configuration Tool (NetCFcfg.exe) - Narzędzie które uruchomione na urządzeniu, pokaże nam zainstalowane wersje .NET CF oraz informacje o DLL‘ach znajdujących się w GAC’u. Dodatkowo pozwoli zmienić domyślną wersję Framework‘a na której będą wykonywane wszystkie jak i poszczególne aplikacje (oczywiście te bez pre-definiowanej wersji).
  • NETCF ServiceModel Metadata Tool (NetCFSvcUtil.exe) - Pisząc aplikacje będącą klientem Windows Communication Foundation (WCF) na pewno docenimy tą aplikację. Pozwala ona na generację proxy którego możemy skorzystać w naszej aplikacji. Generalnie jest to odpowiednik desktopowego narzędzia svcutil.exe.
  • Remote Logging Configuration Tool & Log Viewer (NetCFLogging.exe & logviewer.exe) - narzędzia do konfiguracji, opcji logowania, jakie są wbudowane w .NET CF (ładownie assembly, interakcja z kodem natywnym, interakcja z siecią, logowanie błędów etc.) jak i narzędzie do przeglądania tych, że logów.

Jakiś czas temu usilnie próbowałem uruchomić NETCF CLR Profiler i guzik, nic z tego nie wychodziło, co uruchomiłem profilera otrzymywałem error ‘This operation returned because the timeout period expired. (Exception from HRESULT: 0×800705B4) 800705b4‘.
Problem okazał się być prosty, aplikacja którą próbowałem przetestować, korzystała z .NET CF 2.0, a nasze narzędzie jak się później eksperymentalnie dowiedziałem nie jest z nią kompatybilne. Proste prze-kompilowanie aplikacji w Visual Studio 2008 też nic nie da gdyż musimy, zmienić docelową platformę, co w moim przypadku prowadziło do jakiś dziwnych błędów typu ‘Unknown type to set.‘. Jeszcze nie miałem czasu sprawdzić o co chodzi z tym błędem ale podejrzewam, że jest to powiązane z SQL Compact Edition 2.0/3.5 i różnymi wersjami plików *.sdf.

Najprostszym sposobem upewnienia się, że nasza aplikacja (skompilowana w Visual Studio 2005) będzie pracowała na platformie w wersji 3.5 jest skorzystanie z Application Configuration Tool (NetCFcfg.exe). Innym sposobem jest jawne określenie pożądanej wersji w pliku konfiguracyjnym aplikacji (<app_name.exe.config>). Przykładowy plik może wyglądać następująco:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
  <startup>
    <supportedRuntime version=”v3.5.7283″/>
  </startup>
  <runtime>
    <compatibilityversion major=”3.5″ minor=”0″/>
  </runtime>
</configuration>

Oczywiście plik konfiguracyjny należy umieścić w katalogu głównym naszej aplikacji. Ten sposób, jest bardziej przydatny w sytuacji, gdy robimy deployment aplikacji na wiele urządzeń i chcemy się upewnić, że wszystkie będą pracowały pod kontrolą określonej wersji platformy .NET.

Detekcja wersji pliku *.sdf

grudzień 11, 2007

Nie tak dawno temu pisałem o sposobie aktualizacji bazy Microsoft SQL Compact Edition do wersji 3.5, i już wtedy zastanawiałem się, jak w sposób programowy określić wersję pliku bazy danych. Szybkie sprawdzenie namespace’ów nie dało mi niczego, co mogłoby być użyteczne. Nie mogę powiedzieć, żebym był zaskoczony, żaden zespół developerski nie jest idealny. Wpisałem sobie, więc to pytanie na moją listę ToDo i … jakoś nie miałem czasu się tym zainteresować.
Dzisiaj przeglądając poranną porcję ‘prasy’, natrafiłem na post pana João Paulo Figueiry, traktujący właśnie o wyżej wymienionym problemie. Są, więc dwa sposoby pierwszy, prosty, nieelegancki i uciążliwy - to otwieranie pliku kolejno w różnych wersjach SQL Compact Edition, jak otrzymujemy Exception to znaczy, że plik nie pasuje do aktualnie używanej wersji. Oczywiście musimy mieć zainstalowane wszystkie wersje SQL CE na naszym urządzeniu. Innym sposobem jest otworzenie pliku i odczytaniu kilku bajtów określających wersję pliku. Ciekaw jestem czy autor określił te wartości doświadczalnie, czy też zostały one podane przez Microsoft. Najważniejsze, że sposób działa, gdzie należy szukać i jakich wartości, można znaleźć z załączonym przykładzie.

WCF for Device Developers

listopad 30, 2007

Dla wszystkich zainteresowanych wykorzystaniem Windows Communication Foundation (WCF) do komunikacji z urządzeniami mobilnymi - na stronie OpenNETCF Community pojawił się ciekawy post - An Introduction to WCF for Device Developers. Autor w artykule przedstawia minimum tego co musimy zrobić aby aby utworzyć host’a usługi WCF a następnie go ’skonsumować’ na platformie .NET Compact Framework. Jest to chyba jedyny post tego typu, jaki udało mi się dotychczas znaleźć. Odnoszę takie wrażenie, że wszystkie nowinki jak WCF, LINQ, MS Synchronization Services - traktują platformę Compact Framework nieco po macoszemu i narzędzie do ich obsługi są opisywane tylko tak przy okazji.

Aktualizacja bazy danych

listopad 27, 2007

Najnowsza wersja Sql Server Compact Edition nosi numer 3.5 taki sam jak .NET Framework, co jest naprawdę miłe. Pomyślmy przecież, mógł on zostać ochrzczony numerkiem takim jak np. 3.79 i jeśli weźmiemy pod uwagę długą historię zmian, nazw tegoż produktu - moglibyśmy mieć problem ze spamiętaniem tego wszystkiego. Tą nieco sarkastyczną dygresją, odbiegłem od tematu, który chciałem poruszyć. Otóż wersja 3.1 (i wcześniejsze) nie są kompatybilne z wersją 3.5 Sql Server Compact Edition a wszelkie próby otwarcia definitywnie zakończą się fiaskiem. Aby więc wykorzystać aktualnie istniejące bazy musimy je zaktualizować. Możemy to zrobić w dwojaki sposób, po pierwsze możemy skorzystać z narzędzia update.exe, które jest dostarczane razem z instalacją SQL Server CE (przykładowo dla WM5 z procesorem ARM program domyślnie znajduje się tutaj: c:\Program Files\Microsoft SQL Server Compact Edition\v3.5\Devices\wce500\armv4i\) lub zrobić to z poziomu kodu. Ponieważ korzystanie z aplikacji ‘konsolowych’ w Windows Mobile jest nieco utrudnione, wybrałem łatwiejszą drogę:

string path = Path.GetDirectoryName(
                Assembly.GetExecutingAssembly().GetName().CodeBase)
                + “\\LangLearn.sdf”;

string conn = string.Format(“Data Source={0};”, path);
using(SqlCeEngine engine = new SqlCeEngine(conn))
{
    engine.Upgrade(conn);
}

I gotowe, nasz plik sdf został zaktualizowany.

Emulator i pre-konfigurowany obraz systemu

listopad 26, 2007

Jedną z niedogodności pracy z różnymi aplikacjami mobilnymi, jest konieczność zmiany konfiguracji emulatora dla każdej z nich. Nie jest to może reguła, ale z mojego doświadczenia wynika, że zachodzi ona dość często. Przykładowo zajmuję się aplikacją, w której różni klienci mają zupełnie inne ustawienia urządzeń – teraz, w przypadku problemów muszę uruchomić emulator, zmienić ustawienia, zrestartować emulator, utworzyć bazę danych odpowiednią do poczynionych zmian i na koniec dokonać transferu danych. Dopiero wtedy jestem wstanie rozpocząć diagnozowanie problemu. Oczywiście cała procedura zajmuje dobrych kilka minut. Fajnie by było np. zapisać sobie obraz tak skonfigurowanego emulatora w jakimś osobnym miejscu do późniejszego wykorzystania. Co ciekawsze jest to możliwe.

W ustawieniach Visual Studio w zakładce Devices - wybieramy obraz systemu, z którego chcemy skorzystać i klikamy ‘Save As…’.

Visual Studio Device Settings

Windows Mobile System Image Save As

Podajemy nazwę, pod jaką, nasz nowy system, będzie wyświetlany na liście Device Emulator Managera. Teraz tak spreparowany obraz systemu uruchamiamy instalujemy/konfigurujemy co trzeba i na koniec zapisujemy jego aktualny stan za pomocą ‘Save State and Exit’.

Device Emulator Manager