BlipMobile 1.1.0.0
Nowa wersja Blip Mobile do pobrania tutaj. Aktualna wersja 1.1.0.0 posiada dodatkowo obsługę przycisków przewijania w panelach.
BlipMobile 1.0.0.0
Podczas używania Blip-a bardzo mi brakowało aplikacji na Windows Mobile. Dlatego postanowiłem ją sam napisać. Aplikacja wykorzystuje moje API BlipNet.
Program pozwala na dostęp do bliposfery, najnowszych zdjęć, kokpitu (wymaga zalogowania) oraz pozwala wrzucać własne statusy wraz ze zdjęciem z telefonu oraz aparatu. Aplikacja pozwala na zmianę czasów odświeżania poszczególnych paneli oraz w przypadku zdjęć na ustalenie pobieranej ilości.
Program wymaga .NET-a w wersji 3.5, pisany był pod ekrany QVGA (320×240 / 240×320). Wspiera także ekran dotykowy w przewijaniu poszczególnych paneli.
Aplikacje można ściągnać tutaj w postaci pliku CAB, który trzeba ActiveSync-iem wysłać na telefon.
Wszelkie problemy z aplikacją można zgłaszać w komentarzach pod postem.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Półprzezroczyste grafiki .NET Compact Framework
W jednym z poprzednich artykułów opisywałem sposób wyrysowywania grafik z użyciem ColorKey aby uzyskać efekt przezroczystości. W tym artykule chciałbym poruszyć temat grafik o stałym ustalonym przez nas kanale alfa.
Aby uzyskać efekt półprzezroczystości wykorzystamy funkcję AlphaBlend z biblioteki coredll.dll. Po szczegóły na temat tej metody zapraszam na http://www.pinvoke.net ponieważ ja w tym artykule ograniczę się tylko do części wspieranej przez .NET CF:
[DllImport("coredll.dll")]
private extern static int AlphaBlend(IntPtr hdcDest, int xDest, int yDest, int cxDest, int cyDest, IntPtr hdcSrc, int xSrc, int ySrc, int cxSrc, int cySrc, BlendFunction blendFunction);
private struct BlendFunction
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
}
W BlendFunction możemy tylko ustawić SourceConstantAlpha, czyli stałe alfa dla grafiki. Poniżej prosty class extension:
internal static class GraphicsExtensions
{
internal static void AlphaBlend(this Graphics source, Graphics destination, byte alpha, int xSrc, int ySrc, int wSrc, int hSrc, int xDest, int yDest, int wDest, int hDest)
{
IntPtr hdcDst = source.GetHdc();
IntPtr hdcSrc = destination.GetHdc();
BlendFunction blendFunction = new BlendFunction();
blendFunction.BlendOp = 0; // jedyna wspierana operacja
blendFunction.BlendFlags = 0; // dokumentacja zaleca wstawienie tutaj ?0?
blendFunction.SourceConstantAlpha = alpha; // nasze alfa
blendFunction.AlphaFormat = 0; // wyłączone alfa na pixel
AlphaBlend(hdcDst, xDest, yDest, wDest, hDest, hdcSrc, xSrc, ySrc, wSrc, hSrc, blendFunction);
source.ReleaseHdc(hdcSrc);
destination.ReleaseHdc(hdcDst);
}
}
Teraz wystarczy tylko na istniejącego Graphics-a nałożyć drugiego z określoną grafiką:
using (Bitmap colorImage = new Bitmap(128, 128))
{
using (Graphics gCi = Graphics.FromImage(colorImage))
{
gCi.Clear(Color.Red);
g.AlphaBlend(gCi, 192,
0, 0, colorImage.Width, colorImage.Height,
0, 0, colorImage.Width, colorImage.Height);
}
}
W przypadku jak powyżej g jest naszym aktualnym graphicsem na którym rysujemy. Graphics gCi to jest pokolorowany na czerwono kwadrat, któremu nadajemy alfa o wartości 192. Oczywiście nic nie stoi na przeszkodzie aby używać dowolnych “rysowalnych” elementów jak w screenie poniżej:
Designery kontrolek w .NET Compact Framework
Ktokolwiek tworzył edytory kontrolek w Windows Forms, wie że jest to droga przez mękę. Jednak to co go czeka w Compact Framework można tylko nazwać drogą przez piekło
O ile w standardowych Form-sach designer może być zawarty w bibliotece kontrolki w CF jest to niewykonalne. Wynika to z błahej przyczyny – braku implementacji edytorów w bibliotekach CF. A więc jak to zrobić?
Tworzenie edytora dla określonej kontrolki musimy zacząć od stworzenia Windows Class Library:
Kolejnym krokiem jest dodanie referencji do System.Design abyśmy uzyskali dostęp do base-owych edytorów:
W tak przygotowaną bibliotekę możemy dodać naszą klasę edytora. W naszym przykładzie stworzymy klasę edytora dla kontrolki ToolBar:
internal class ToolBarDesigner : ControlDesigner
{
public ToolBarDesigner()
{
}
}
Zadaniem tego designera będzie powiązanie buttonów dziedziczących po klasie Component z naszym ToolBar-em. Powiązanie to jest wymagane przy wykonywaniu przenoszenia / kopiowania ToolBar-a z jednego form-a na drugi. Zrealizujemy je przez przeciążenie właściwości AssociatedComponents ControlDesigner-a:
public override ICollection AssociatedComponents
{
get
{
ToolBar control = this.Control as ToolBar;
if (control != null)
{
return control.Buttons;
}
return base.AssociatedComponents;
}
}
Następnym krokiem jest powiązanie naszego designera z konkretną kontrolką. Aby to uzyskać musimy wskazać naszemu ToolBar-owi jakiego edytora ma używać. Jednak nie możemy tego wykonać przez bezpośrednie wskazanie klasy a przez referencję do biblioteki.
Na początek podpisujemy bibliotekę kluczem:
W kolejnym kroku musimy ją zarejestrować w Global Assembly Cache. Aby sobie ułatwić zadanie możemy rejestrowanie dodać do zdarzeń po kompilacji:
“C:Program FilesMicrosoft Visual Studio 8SDKv2.0Bingacutil.exe” /u “$(TargetName)”
“C:Program FilesMicrosoft Visual Studio 8SDKv2.0Bingacutil.exe” /i “$(TargetPath)”
Pierwsza linijka wyrejestrowuje bibliotekę a druga rejestruje.
Ostatnim krokiem powiązania jest wskazanie w pliku Design-Time Attribute klasy (o tych plikach pisałem w tym artykule), która ma być użyta jako edytor:
<?xml version="1.0" encoding="utf-16"?> <Classes xmlns="http://schemas.microsoft.com/VisualStudio/2004/03/SmartDevices/XMTA.xsd"> <Class Name="Cubicsoft.WindowsMobile.Controls.ToolBar"> <Designer> <Type>Cubicsoft.WindowsMobile.Controls.Design.ToolBarDesigner, Cubicsoft.WindowsMobile.Controls.Design, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c223de6bc083912b</Type> <BaseType></BaseType> </Designer> </Class> </Classes> </xml>
W wyniku otrzymujemy funkcjonalność przenoszenia powiązanych komponentów między form-ami.
Atrybuty designerów w kontrolkach .NET Compact Framework
Każdy kto kiedykolwiek stworzył choćby jedną kontrolkę w Compact Framework zauważył, że ilość atrybutów właściwości / klas jest bardzo ograniczona. Praktycznie .NET CF implementuje tylko następujące atrybuty:
- DefaultValueAttribute (tylko w wersji jedno parametrowej gdzie można podać wartość)
- DesignTimeVisibleAttribute
- EditorBrowsableAttribute
Brak ten wynika z faktu, iż .NET Compact Framework nie wspiera automatycznie Visual Studio designerów.
Aby zapewnić sobie pełen wachlarz atrybutów trzeba do projektu dodać plik design-time atrybutów:

Dodany plik ma następującą zawartość:
<?xml version="1.0" encoding="utf-16"?> <Classes xmlns="http://schemas.microsoft.com/VisualStudio/2004/03/SmartDevices/XMTA.xsd"> </Classes>
Aby dodać kontrolkę wystarczy dodać następujący element:
<Class Name="Cubicsoft.WindowsMobile.Controls.Label"> </Class>
Kolejne klasy muszą być potomkiem “Classes”. Choć wg. mnie dobrym zwyczajem jak w przypadku “zwykłych” klas jest przyjęcie zasady: jeden plik na jedną kontrolkę.
Warto rozpocząć definiowanie parametrów od atrybutu DesktopCompatible, aby ustrzec się błędęm “Visual Inheritance is Currently Disabled” który może się pojawić w momencie dodania kontrolki do Form-a:
// włączenie DesktopCompatible <DesktopCompatible>true</DesktopCompatible>
Kolejne elementy jak DefaultProperty, DefaultEvent itp. dotyczą oczywiście klasy.
Właściwości definiujemy w następujący sposób:
<Property Name="BorderStyle"> <Category>Appearance</Category> <Description>Indicates whether the label should have a border.</Description> </Property>
Edytor w pełni wspiera IntelliSense, więc pisanie kolejnych elementów jest dziecinnie proste.
Wynikowy plik dla kontrolki Label może wyglądać tak:
<?xml version="1.0" encoding="utf-16"?> <Classes xmlns="http://schemas.microsoft.com/VisualStudio/2004/03/SmartDevices/XMTA.xsd"> <Class Name="Cubicsoft.WindowsMobile.Controls.Label"> <DesktopCompatible>true</DesktopCompatible> <DefaultProperty>Text</DefaultProperty> <Property Name="BorderStyle"> <Category>Appearance</Category> <Description>Indicates whether the label should have a border.</Description> </Property> <Property Name="BorderColor"> <Category>Appearance</Category> <Description>The border color of this component.</Description> </Property> </Class> </Classes>
Po zapisaniu i skompilowaniu biblioteki otrzymamy dodatkowy plik o rozszerzeniu [Nazwa biblioteki].PocketPC.asmmeta.dll jest to biblioteka, która zawiera nasze nowe definicję atrybutów dla designerów.
BlipNet 0.2.1.0
Kolejna odsłona BlipNet-a. Poprawki względem poprzedniej wersji:
- implementacja uploadu obazków (Avatar, Background, Update, Status, itp)
- poprawka na tworzenie subskrypcji
- implementacja delegatora statusu upload-u
Aktualna wersja jest wersją stabilną, po testach praktycznych około 70% funkcjonalności.
BlipNet 0.2.0.1
Kolejna odsłona BlipNet-a. Poprawki względem poprzedniej wersji:
- poprawiona “autoryzacja” w przypadku gdy nie podano loginu i hasła
- usunięty Image z typów graficznych
- usunięty Helpers.cs do ściągania plików
- dodanie UriConverter-a na typy Uri
Przezroczyste grafiki w .NET Compact Framework
Compact Framework nie wspiera rysowania przezroczystych grafik. Wszelkie rysowanie grafiki PNG lub GIF (z przezroczystością) zakończy się efektem jak poniżej:

Grafika ToolBar-a wyrysowała się z zielonym tłem, ponieważ ten kolor był ustawiony jako kolor przezroczysty.
Kod użyty do rysowania:
// Grafika z resources Image img = Properties.Resources.Buttons; // Rysowanie graphics.DrawImage(img, 0, 0);
Możemy jednak w prosty sposób wskazać Graphics-owi kolor, który ma zostać pominięty podczas rysowania, aby uzyskać efekt jak poniżej:

Grafika tym razem wyrysowała się poprawnie, pomijając kolor przezroczystości.
Aby uzyskać taki efekt musimy wskazać Graphics-owi kolor (w praktyce jest to przedział kolorów), które mają być potraktowane jako przezroczyste.
Kod użyty do rysowania:
// Grafika z resources Image img = Properties.Resources.Buttons; // Atrybuty grafiki ImageAttributes imageAttr = new ImageAttributes(); Color colorKey = new Bitmap(img).GetPixel(0, 0); imageAttr.SetColorKey(colorKey, colorKey); graphics.DrawImage(img, new Rectangle(x, 0, img.Width, img.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imageAttr);
W trakcie używania ImageAttributes trzeba pamiętać o kilku rzeczach.
- po pierwsze ColorKey jest przedziałem kolorów, co oznacza iż w przypadku gdy mamy jeden kolor przezroczystości musimy ustawić dolny i górny indeks tak samo.
- po drugie cała sztuczka polega na wskazaniu koloru przezroczystości, w przykładzie jak powyżej użyłem metody GetPixel do pobrania koloru punktu na pozycj 0,0. W praktyce jednak warto zastąpić tą metodę parametrem do ustawiania koloru przezroczystości aby uchronić się przed niespodziankami.
- po trzecie musimy pamiętać iż CF nie wspiera przezroczystych kontrolek, co oznacza iż przed rysowaniem przezroczystej grafiki musimy mieć inne elementy pod spodem aby całość poprawnie wyglądała; może to być nawet kolor tła.
- po czwarte CF nie wspiera grafik o różnej przezroczystości jak np. PNG, więc nie ma szans abyśmy uzyskali przenikające się grafiki.
Na pocieszenie powiem jednak, że mamy dostęp do funkcji AlphaBlend o której napiszę kilka słów w którymś z kolejnych postów.
BlipNet 0.2.0.0
Dziś udało mi się w końcu uruchomić BlipNet-a. Dla niezorientowanych jest to biblioteka dostępowa do API Blip-a. Aktualna wersja to wczesna alfa, ale powoli testuje jej funkcjonalność w innym projekcie na Windows Mobile 6 SDK.
Zdecydowałem się na “toporne” metody HttpWebRequest ze wzlędu na brak nowych rozwiązań a’la WCF w wersji Json w CF.
Przykłady użycia:
// Bliposfera BlipNet.Message[] messages = new BlipNet.BlipService().GetBliposphere();
// Kokpit
BlipNet.Message[] messages = new BlipNet.BlipService("login", "hasło").GetDashboard();
Lepszy MeasureString w .NET Compact Framework
Jeżeli starałeś się zbudować dynamiczne GUI w .NET Compact Framework, prawdopodobnie zauważyłeś niedostatek metody MeasureString z parametrem SizeF.
W .NET CF, Graphics ma tylko jedną metodę mierzenia napisów:
///
/// Measures the specified string when drawn with the specified Font.
///
public SizeF MeasureString(string text, Font font);
Dla długiego napisu w którym nie ma znaków łamania powyższa metoda zwraca kosmicznie długi rozmiar.
Jeżeli pisałeś wcześniej w wersji desktopowej to pewnie zauważyłeś, że jest wersja tej metody z parametrem SizeF, który określa docelowy rozmiar w który napis będzie wpasowywany i łamany. Obejściem tego problemu jest poniższy class extension na Graphicsa, który przyjmuje parametr Rectangle jako prostokąt do wpasowania napisu.
internal static class GraphicExtensions
{
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public Rect(Rectangle r)
{
Left = r.Left;
Top = r.Top;
Bottom = r.Bottom;
Right = r.Right;
}
}
public static SizeF MeasureString(this Graphics graphic, string text, Font font, Rectangle rectangle)
{
Rect bounds = new Rect(rectangle);
IntPtr hFont = font.ToHfont();
IntPtr hDc = graphic.GetHdc();
IntPtr originalObject = SelectObject(hDc, hFont);
DrawText(hDc, text, text.Length, ref bounds, DT_CALCRECT | DT_WORDBREAK);
SelectObject(hDc, originalObject);
graphic.ReleaseHdc(hDc);
return new SizeF(bounds.Right - bounds.Left, bounds.Bottom - bounds.Top);
}
private static int DT_CALCRECT = 0x00000400;
private static int DT_WORDBREAK = 0x00000010;
[DllImport("coredll.dll")]
private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("coredll.dll")]
private static extern int DrawText(IntPtr hdc, string lpStr, int nCount, ref Rect lpRect, int wFormat);
}













