Z racji tego, że moja aplikacja jest już w fazie testów nie-u-mnie, byłem zmuszony napisać jakiś sposób do zgłaszania błędów – próba odtworzenia błędu u siebie(czy to na emulatorze, czy też telefonie) była bardzo trudna, albo wręcz niemożliwa. Nie sposób było powielić każde warunki(wersję oprogramowania, specyfikację urządzania, konfigurację samej aplikacji, o której zapominałem albo nie byłem w stanie się jej dowiedzieć). Jako iż od jakiegoś czasu staram się nie kombinować z robieniem jakichś pseudo-uniwersalnych i przekombinowanych cudów, zrobiłem to po najmniejszej linii oporu –
raport to zwykły mail(albo nawet nie, ale o tym za chwilę) z najpotrzebniejszymi informacjami(log, informacje o urządzeniu, informację od użytkownika).
Pisząc kolejny projekt, miałem sobie oto taki kod:
return this->Send(&msgSize, sizeof(MessageSizeType)) + this->Send(&catLength, sizeof(MessageCatLengthType)) + this->Send(category.c_str(), catLength * sizeof(wchar_t)) + this->Send(msg.c_str(), msg.length() * sizeof(wchar_t));
Nie wydaje mi się bardzo skomplikowany. Powinno wystarczyć, gdy zaznaczę, że wysyła on jedną „wiadomość” przez sieć – ot, 5 pierwszych bajtów to nagłówek(MessageSizeType – unsigned, MessageCatLengthType – unsigned char) a reszta dane. Oczywiście MUSZĄ być one dostarczone wszystkie, w takiej kolejności w jakiej są, więc wszystko leci po TCP. Pytanie: co tu jest źle?
Ostatnimi czasy dość dużo siedzę w Javie, programując na Androida(Kingdoms Clash.NET zostało niestety porzucone, ale o tym kiedy indziej (może)). Rozwijam swój stary projekt(w końcu!), który od początku miał być dość mocno związany z platformami mobilnymi. Mam tylko telefon z Androidem, więc na nim się skupiłem. Java nie jest moim ulubionym językiem, ale niestety zostałem „zmuszony” do poznania go ciut głębiej. Suma sumarum zły nie jest, lecz kilka rzeczy naprawdę mnie wkurza. Przy moim pierwszym spotkaniu z nim miałem problem z ogarnięciem obsługi nieblokujących gniazd – nie mogłem trafić na sensowne informacje o tym, tym razem miałem ciut więcej samozaparcia i udało mi się rozgryźć ten problem i stwierdziłem, że warto bym to, nawet jeśli będzie tylko dla mnie, zapisał. Mimo iż Java jest językiem bardzo wysokopoziomowym, obsługa gniazd jest… niskopoziomowa jak w C(C# też ma to dość niskopoziomowo zrobione, lecz nie odbiega bardzo od reszty)!
Pisząc(powoli bo powoli, ale pisząc) rozgrywkę sieciową do Kingdoms Clash.NET, odkładałem „na potem” synchronizację dostępu do danych. Nie używam wielu wątków – ot 2 per aplikacja – ale problem dał się we znaki. W końcu stwierdziłem, że nie ma co się bawić w odkładanie tego i trzeba to napisać. Jak postanowiłem tak zrobiłem i wynik mnie zadowala. Czytaj dalej…
Jakiś czas temu poruszałem temat poruszania się jednostek. Z braku pomysłu rozwiązałem to najprostszą działającą metodą – bezpośrednią zmianą pozycji jednostki. Oprócz tego, że działało nie miało zalet. Od tego czasu upłynęło trochę wody w Wiśle jak i gra się „ciut” rozwinęła. Któregoś pięknego dnia postanowiłem się za to zabrać i ponownie podszedłem do problemu. Teraz już nie próbowałem pisać prototypu w grze, lecz od razu zaopatrzyłem się w XNA Game Studio(tym razem wersję 4.0) i Testbed. Czytaj dalej…
Jak obiecałem w poprzednim w poprzednim wpisie, przedstawię teraz ciut bardziej sensowne rozszerzenie, niż to, które pokazałem w pierwszym poście z tej serii. A będzie to bardzo prosty binding. Przy pisaniu tego rozszerzenia do silnika(które to jest dostępne na GitHubie) pokusiłem się o implementację podobną do tej z WPF. Co prawda nie używałem DependencyProperty, ale i tak stwierdzam, że jest to przerost formy nad treścią. Niemniej jestem z tego dumny ![]()
Czytaj dalej…
Dziś natknąłem się na coś, z czym nie potrafię sobie poradzić. W mojej implementacji bindingów pobieram obiekt źródłowy przez IXamlNameResolver(który to pokrótce opisałem w poprzedniej notce) – wszystko działa pięknie, dopóki nie zachcemy odwoływać się do obiektu-rodzica dodatkowo odwołując się do niego z innego miejsca. Ciężko to opisać słowami, kod najlepiej to zobrazuje:
<Element x:Name="el1" Value="{Binding Source=el2,Path=Value}" />
<Element x:Name="el2" Value="5">
<SubElement Value="{Binding Source=el2,Path=Value}" />
</Element>
Gdy zakomentuje sobie pierwszy element(a co za tym idzie i wiązanie) wszystko działa jak należy. Jednak gdy on istnieje… zaczynają się dziać cuda
Gdy parser XAML przechodzi w fazę reparsowania grafu rozwiązuje pierwszą zależność(ten zewnętrzny binding) i przy drugim… rzuca wyjątkiem KeyNotFoundException z jakże wiele mówiącym callstackiem:
at System.Collections.Generic.Dictionary`2.get_Item(TKey key) at MS.Internal.Xaml.Context.NameFixupGraph.<GetRemainingReparses>d__a.MoveNext() at System.Xaml.XamlObjectWriter.CompleteNameReferences() at System.Xaml.XamlObjectWriter.WriteEndObject() at System.Xaml.XamlServices.Transform(XamlReader xamlReader, XamlWriter xamlWriter, Boolean close Writer)
Przekonać się o tym można pobierając ten commit.
Próbowałem różnych kombinacji – przenosiłem element nad, pod, z boku, z lewej, z prawej, dodawałem inne – nic. A wystarczy zakomentować ten wewnętrzny element…
Zastanawiam się, czy nie trafiłem przypadkiem na jakiś bug w .NET Frameworku. Jest to sprzeczne z tym, co napisał Xion w jednej ze swoich notek, ale chwilowo nie widzę innego rozwiązania, tym bardziej, że występuje to tylko pod jednym, jedynym warunkiem. Dodatkowo „na nie” przemawia fakt, że w WPF coś takiego działa(z tym, że jest tam to inaczej rozwiązane). Może ktoś z Was się z czymś takim spotkał w swojej karierze, ewentualnie widzi błąd w moim kodzie?
Ostatnio pokazywałem, jak napisać proste rozszerzenie XAML – opisałem, jak stworzyć parametrowe i bezparametrowe rozszerzenie. Dziś skupię się na metodzie ProvideValue, a dokładniej na dostawcy usług, który przekazywany jest nam w parametrze. Czytaj dalej…
Ostatnio cały czas bawiłem się XAML-em, by w końcu doprowadzić system GUI to względnej używalności. Temat ten jest na osobną notkę, która możliwe, że pojawi się niedługo ![]()
XAML w standardzie jest już dość rozbudowany. Lecz gdyby to nam nie wystarczało(a czasami nie wystarcza), daje nam możliwość jeszcze większej rozbudowy. Wystarczy odziedziczyć z klasy MarkupExtension, by móc korzystać z własnych rozszerzeń(dostępnych za pomocą sekwencji ucieczki {}). Ale jak to się robi w praktyce?
W poprzednim odcinku skupiłem się raczej na grze(i jak ją można ulepszyć) niż na, jak tytuł wskazywał, serializacji. Tak szczerze powiedziawszy to o grze samej w sobie jest bardzo mało wpisów, więcej jest o tym, czego użyłem, początkach z bibliotekami czy bojami z silnikiem. Przyznam, że nie wiem, czym to jest do końca spowodowane, możliwe, że gra jest od strony technicznej mało ciekawa
Na początku miałem zamiar opisać wszystkie znane mi sposoby na to, lecz po przemyśleniach stwierdziłem, że jest to bez sensu. W Internecie jest już tyle tekstów na ten temat(np. MSDN), że nie ma potrzeby, bym powielał to, co już jest. Opiszę natomiast to, czego ja użyłem i dlaczego akurat tego. Czytaj dalej…