Jakub Florczyk - Blog o programowaniu .NET

Programista praktyczny

Tag: Silverlight

Niestandardowe kodowanie tekstu w Silverlight

W przeciwieństwie do “standardowej” platformy .NET, Silverlight (w wersji webowej oraz na Windows Phone) dostarcza tylko dwa wbudowane kodowania: UTF-8 oraz UTF-16.

Aby uzyskać inne kodowania należy napisać własną klasę Encoding. A ponieważ wciąż zdarzają się w internecie serwisy kodowane w np. typowym tylko dla Polski ISO-8859-2 z pomocą przychodzi narzędzie SL Encoding Generator. Aplikacja pozwala na proste i szybkie wygenerowanie klasy Encoding dla podanej strony kodowej, którą natychmiast możemy użyć w naszym programie.

Przykładowa wygenerowana klasa dla kodowania ISO-8859-2 wygląda następująco:

///

/// A custom encoding class that provides encoding capabilities for the
/// 'Środkowoeuropejski (ISO)' encoding under Silverlight.
/// This class was generated by a tool. For more information, visit /// http://www.hardcodet.net/2010/03/silverlight-text-encoding-class-generator ///
public class IsoEncoding : Encoding { /// /// Gets the name registered with the /// Internet Assigned Numbers Authority (IANA) for the current encoding. /// /// /// The IANA name for the current . /// public override string WebName { get { return "iso-8859-2"; } } private char? fallbackCharacter; /// /// A character that can be set in order to make the encoding class /// more fault tolerant. If this property is set, the encoding class will /// use this property instead of throwing an exception if an unsupported /// byte value is being passed for decoding. /// public char? FallbackCharacter { get { return fallbackCharacter; } set { fallbackCharacter = value; if (value.HasValue && !charToByte.ContainsKey(value.Value)) { string msg = "Cannot use the character [{0}] (int value {1}) as fallback value " + "- the fallback character itself is not supported by the encoding."; msg = String.Format(msg, value.Value, (int)value.Value); throw new EncoderFallbackException(msg); } FallbackByte = value.HasValue ? charToByte[value.Value] : (byte?)null; } } /// /// A byte value that corresponds to the . /// It is used in encoding scenarios in case an unsupported character is /// being passed for encoding. /// public byte? FallbackByte { get; private set; } public IsoEncoding() { FallbackCharacter = '?'; } /// /// Encodes a set of characters from the specified character array into the specified byte array. /// /// /// The actual number of bytes written into . /// /// The character array containing the set of characters to encode. /// The index of the first character to encode. /// The number of characters to encode. /// The byte array to contain the resulting sequence of bytes. /// The index at which to start writing the resulting sequence of bytes. /// public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { return FallbackByte.HasValue ? GetBytesWithFallBack(chars, charIndex, charCount, bytes, byteIndex) : GetBytesWithoutFallback(chars, charIndex, charCount, bytes, byteIndex); } private int GetBytesWithFallBack(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { for (int i = 0; i < charCount; i++) { var character = chars[i + charIndex]; byte byteValue; bool status = charToByte.TryGetValue(character, out byteValue); bytes[byteIndex + i] = status ? byteValue : FallbackByte.Value; } return charCount; } private int GetBytesWithoutFallback(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { for (int i = 0; i < charCount; i++) { var character = chars[i + charIndex]; byte byteValue; bool status = charToByte.TryGetValue(character, out byteValue); if (!status) { //throw exception string msg = "The encoding [{0}] cannot encode the character [{1}] (int value {2}). Set the FallbackCharacter property in order to suppress this exception and encode a default character instead."; msg = String.Format(msg, WebName, character, (int)character); throw new EncoderFallbackException(msg); } bytes[byteIndex + i] = byteValue; } return charCount; } /// /// Decodes a sequence of bytes from the specified byte array into the specified character array. /// /// /// The actual number of characters written into . /// /// The byte array containing the sequence of bytes to decode. /// The index of the first byte to decode. /// The number of bytes to decode. /// The character array to contain the resulting set of characters. /// The index at which to start writing the resulting set of characters. /// public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { return FallbackCharacter.HasValue ? GetCharsWithFallback(bytes, byteIndex, byteCount, chars, charIndex) : GetCharsWithoutFallback(bytes, byteIndex, byteCount, chars, charIndex); } private int GetCharsWithFallback(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { for (int i = 0; i < byteCount; i++) { byte lookupIndex = bytes[i + byteIndex]; //if the byte value is not in our lookup array, fall back to default character char result = lookupIndex >= byteToChar.Length ? FallbackCharacter.Value : byteToChar[lookupIndex]; chars[charIndex + i] = result; } return byteCount; } private int GetCharsWithoutFallback(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { for (int i = 0; i < byteCount; i++) { byte lookupIndex = bytes[i + byteIndex]; if (lookupIndex >= byteToChar.Length) { //throw exception string msg = "The encoding [{0}] cannot decode byte value [{1}]. Set the FallbackCharacter property in order to suppress this exception and decode the value as a default character instead."; msg = String.Format(msg, WebName, lookupIndex); throw new EncoderFallbackException(msg); } chars[charIndex + i] = byteToChar[lookupIndex]; } return byteCount; } /// /// Calculates the number of bytes produced by encoding a set of characters /// from the specified character array. /// /// /// The number of bytes produced by encoding the specified characters. This class /// alwas returns the value of . /// public override int GetByteCount(char[] chars, int index, int count) { return count; } /// /// Calculates the number of characters produced by decoding a sequence /// of bytes from the specified byte array. /// /// /// The number of characters produced by decoding the specified sequence of bytes. This class /// alwas returns the value of . /// public override int GetCharCount(byte[] bytes, int index, int count) { return count; } /// /// Calculates the maximum number of bytes produced by encoding the specified number of characters. /// /// /// The maximum number of bytes produced by encoding the specified number of characters. This /// class alwas returns the value of . /// /// The number of characters to encode. /// public override int GetMaxByteCount(int charCount) { return charCount; } /// /// Calculates the maximum number of characters produced by decoding the specified number of bytes. /// /// /// The maximum number of characters produced by decoding the specified number of bytes. This class /// alwas returns the value of . /// /// The number of bytes to decode. public override int GetMaxCharCount(int byteCount) { return byteCount; } /// /// Gets the number of characters that are supported by this encoding. /// This property returns a maximum value of 256, as the encoding class /// only supports single byte encodings (1 byte == 256 possible values). /// public static int CharacterCount { get { return byteToChar.Length; } } #region Character Table /// /// This table contains characters in an array. The index within the /// array corresponds to the encoding's mapping of bytes to characters /// (e.g. if a byte value of 5 is used to encode the character 'x', this /// character will be stored at the array index 5. /// private static char[] byteToChar = new char[] { (char)0 /* byte 0 */ , (char)1 /* byte 1 */ , (char)2 /* byte 2 */ , (char)3 /* byte 3 */ , (char)4 /* byte 4 */ , (char)5 /* byte 5 */ , (char)6 /* byte 6 */ , (char)7 /* byte 7 */ , (char)8 /* byte 8 */ , (char)9 /* byte 9 */ , (char)10 /* byte 10 */ , (char)11 /* byte 11 */ , (char)12 /* byte 12 */ , (char)13 /* byte 13 */ , (char)14 /* byte 14 */ , (char)15 /* byte 15 */ , (char)16 /* byte 16 */ , (char)17 /* byte 17 */ , (char)18 /* byte 18 */ , (char)19 /* byte 19 */ , (char)20 /* byte 20 */ , (char)21 /* byte 21 */ , (char)22 /* byte 22 */ , (char)23 /* byte 23 */ , (char)24 /* byte 24 */ , (char)25 /* byte 25 */ , (char)26 /* byte 26 */ , (char)27 /* byte 27 */ , (char)28 /* byte 28 */ , (char)29 /* byte 29 */ , (char)30 /* byte 30 */ , (char)31 /* byte 31 */ , (char)32 /* byte 32 */ , (char)33 /* byte 33 */ , (char)34 /* byte 34 */ , (char)35 /* byte 35 */ , (char)36 /* byte 36 */ , (char)37 /* byte 37 */ , (char)38 /* byte 38 */ , (char)39 /* byte 39 */ , (char)40 /* byte 40 */ , (char)41 /* byte 41 */ , (char)42 /* byte 42 */ , (char)43 /* byte 43 */ , (char)44 /* byte 44 */ , (char)45 /* byte 45 */ , (char)46 /* byte 46 */ , (char)47 /* byte 47 */ , (char)48 /* byte 48 */ , (char)49 /* byte 49 */ , (char)50 /* byte 50 */ , (char)51 /* byte 51 */ , (char)52 /* byte 52 */ , (char)53 /* byte 53 */ , (char)54 /* byte 54 */ , (char)55 /* byte 55 */ , (char)56 /* byte 56 */ , (char)57 /* byte 57 */ , (char)58 /* byte 58 */ , (char)59 /* byte 59 */ , (char)60 /* byte 60 */ , (char)61 /* byte 61 */ , (char)62 /* byte 62 */ , (char)63 /* byte 63 */ , (char)64 /* byte 64 */ , (char)65 /* byte 65 */ , (char)66 /* byte 66 */ , (char)67 /* byte 67 */ , (char)68 /* byte 68 */ , (char)69 /* byte 69 */ , (char)70 /* byte 70 */ , (char)71 /* byte 71 */ , (char)72 /* byte 72 */ , (char)73 /* byte 73 */ , (char)74 /* byte 74 */ , (char)75 /* byte 75 */ , (char)76 /* byte 76 */ , (char)77 /* byte 77 */ , (char)78 /* byte 78 */ , (char)79 /* byte 79 */ , (char)80 /* byte 80 */ , (char)81 /* byte 81 */ , (char)82 /* byte 82 */ , (char)83 /* byte 83 */ , (char)84 /* byte 84 */ , (char)85 /* byte 85 */ , (char)86 /* byte 86 */ , (char)87 /* byte 87 */ , (char)88 /* byte 88 */ , (char)89 /* byte 89 */ , (char)90 /* byte 90 */ , (char)91 /* byte 91 */ , (char)92 /* byte 92 */ , (char)93 /* byte 93 */ , (char)94 /* byte 94 */ , (char)95 /* byte 95 */ , (char)96 /* byte 96 */ , (char)97 /* byte 97 */ , (char)98 /* byte 98 */ , (char)99 /* byte 99 */ , (char)100 /* byte 100 */ , (char)101 /* byte 101 */ , (char)102 /* byte 102 */ , (char)103 /* byte 103 */ , (char)104 /* byte 104 */ , (char)105 /* byte 105 */ , (char)106 /* byte 106 */ , (char)107 /* byte 107 */ , (char)108 /* byte 108 */ , (char)109 /* byte 109 */ , (char)110 /* byte 110 */ , (char)111 /* byte 111 */ , (char)112 /* byte 112 */ , (char)113 /* byte 113 */ , (char)114 /* byte 114 */ , (char)115 /* byte 115 */ , (char)116 /* byte 116 */ , (char)117 /* byte 117 */ , (char)118 /* byte 118 */ , (char)119 /* byte 119 */ , (char)120 /* byte 120 */ , (char)121 /* byte 121 */ , (char)122 /* byte 122 */ , (char)123 /* byte 123 */ , (char)124 /* byte 124 */ , (char)125 /* byte 125 */ , (char)126 /* byte 126 */ , (char)127 /* byte 127 */ , (char)128 /* byte 128 */ , (char)129 /* byte 129 */ , (char)130 /* byte 130 */ , (char)131 /* byte 131 */ , (char)132 /* byte 132 */ , (char)133 /* byte 133 */ , (char)134 /* byte 134 */ , (char)135 /* byte 135 */ , (char)136 /* byte 136 */ , (char)137 /* byte 137 */ , (char)138 /* byte 138 */ , (char)139 /* byte 139 */ , (char)140 /* byte 140 */ , (char)141 /* byte 141 */ , (char)142 /* byte 142 */ , (char)143 /* byte 143 */ , (char)144 /* byte 144 */ , (char)145 /* byte 145 */ , (char)146 /* byte 146 */ , (char)147 /* byte 147 */ , (char)148 /* byte 148 */ , (char)149 /* byte 149 */ , (char)150 /* byte 150 */ , (char)151 /* byte 151 */ , (char)152 /* byte 152 */ , (char)153 /* byte 153 */ , (char)154 /* byte 154 */ , (char)155 /* byte 155 */ , (char)156 /* byte 156 */ , (char)157 /* byte 157 */ , (char)158 /* byte 158 */ , (char)159 /* byte 159 */ , (char)160 /* byte 160 */ , (char)260 /* byte 161 */ , (char)728 /* byte 162 */ , (char)321 /* byte 163 */ , (char)164 /* byte 164 */ , (char)317 /* byte 165 */ , (char)346 /* byte 166 */ , (char)167 /* byte 167 */ , (char)168 /* byte 168 */ , (char)352 /* byte 169 */ , (char)350 /* byte 170 */ , (char)356 /* byte 171 */ , (char)377 /* byte 172 */ , (char)173 /* byte 173 */ , (char)381 /* byte 174 */ , (char)379 /* byte 175 */ , (char)176 /* byte 176 */ , (char)261 /* byte 177 */ , (char)731 /* byte 178 */ , (char)322 /* byte 179 */ , (char)180 /* byte 180 */ , (char)318 /* byte 181 */ , (char)347 /* byte 182 */ , (char)711 /* byte 183 */ , (char)184 /* byte 184 */ , (char)353 /* byte 185 */ , (char)351 /* byte 186 */ , (char)357 /* byte 187 */ , (char)378 /* byte 188 */ , (char)733 /* byte 189 */ , (char)382 /* byte 190 */ , (char)380 /* byte 191 */ , (char)340 /* byte 192 */ , (char)193 /* byte 193 */ , (char)194 /* byte 194 */ , (char)258 /* byte 195 */ , (char)196 /* byte 196 */ , (char)313 /* byte 197 */ , (char)262 /* byte 198 */ , (char)199 /* byte 199 */ , (char)268 /* byte 200 */ , (char)201 /* byte 201 */ , (char)280 /* byte 202 */ , (char)203 /* byte 203 */ , (char)282 /* byte 204 */ , (char)205 /* byte 205 */ , (char)206 /* byte 206 */ , (char)270 /* byte 207 */ , (char)272 /* byte 208 */ , (char)323 /* byte 209 */ , (char)327 /* byte 210 */ , (char)211 /* byte 211 */ , (char)212 /* byte 212 */ , (char)336 /* byte 213 */ , (char)214 /* byte 214 */ , (char)215 /* byte 215 */ , (char)344 /* byte 216 */ , (char)366 /* byte 217 */ , (char)218 /* byte 218 */ , (char)368 /* byte 219 */ , (char)220 /* byte 220 */ , (char)221 /* byte 221 */ , (char)354 /* byte 222 */ , (char)223 /* byte 223 */ , (char)341 /* byte 224 */ , (char)225 /* byte 225 */ , (char)226 /* byte 226 */ , (char)259 /* byte 227 */ , (char)228 /* byte 228 */ , (char)314 /* byte 229 */ , (char)263 /* byte 230 */ , (char)231 /* byte 231 */ , (char)269 /* byte 232 */ , (char)233 /* byte 233 */ , (char)281 /* byte 234 */ , (char)235 /* byte 235 */ , (char)283 /* byte 236 */ , (char)237 /* byte 237 */ , (char)238 /* byte 238 */ , (char)271 /* byte 239 */ , (char)273 /* byte 240 */ , (char)324 /* byte 241 */ , (char)328 /* byte 242 */ , (char)243 /* byte 243 */ , (char)244 /* byte 244 */ , (char)337 /* byte 245 */ , (char)246 /* byte 246 */ , (char)247 /* byte 247 */ , (char)345 /* byte 248 */ , (char)367 /* byte 249 */ , (char)250 /* byte 250 */ , (char)369 /* byte 251 */ , (char)252 /* byte 252 */ , (char)253 /* byte 253 */ , (char)355 /* byte 254 */ , (char)729 /* byte 255 */ }; #endregion #region Byte Lookup Dictionary /// /// This dictionary is used to resolve byte values for a given character. /// private static Dictionary charToByte = new Dictionary { { (char)0, 0 }, { (char)1, 1 }, { (char)2, 2 }, { (char)3, 3 }, { (char)4, 4 }, { (char)5, 5 }, { (char)6, 6 }, { (char)7, 7 }, { (char)8, 8 }, { (char)9, 9 }, { (char)10, 10 }, { (char)11, 11 }, { (char)12, 12 }, { (char)13, 13 }, { (char)14, 14 }, { (char)15, 15 }, { (char)16, 16 }, { (char)17, 17 }, { (char)18, 18 }, { (char)19, 19 }, { (char)20, 20 }, { (char)21, 21 }, { (char)22, 22 }, { (char)23, 23 }, { (char)24, 24 }, { (char)25, 25 }, { (char)26, 26 }, { (char)27, 27 }, { (char)28, 28 }, { (char)29, 29 }, { (char)30, 30 }, { (char)31, 31 }, { (char)32, 32 }, { (char)33, 33 }, { (char)34, 34 }, { (char)35, 35 }, { (char)36, 36 }, { (char)37, 37 }, { (char)38, 38 }, { (char)39, 39 }, { (char)40, 40 }, { (char)41, 41 }, { (char)42, 42 }, { (char)43, 43 }, { (char)44, 44 }, { (char)45, 45 }, { (char)46, 46 }, { (char)47, 47 }, { (char)48, 48 }, { (char)49, 49 }, { (char)50, 50 }, { (char)51, 51 }, { (char)52, 52 }, { (char)53, 53 }, { (char)54, 54 }, { (char)55, 55 }, { (char)56, 56 }, { (char)57, 57 }, { (char)58, 58 }, { (char)59, 59 }, { (char)60, 60 }, { (char)61, 61 }, { (char)62, 62 }, { (char)63, 63 }, { (char)64, 64 }, { (char)65, 65 }, { (char)66, 66 }, { (char)67, 67 }, { (char)68, 68 }, { (char)69, 69 }, { (char)70, 70 }, { (char)71, 71 }, { (char)72, 72 }, { (char)73, 73 }, { (char)74, 74 }, { (char)75, 75 }, { (char)76, 76 }, { (char)77, 77 }, { (char)78, 78 }, { (char)79, 79 }, { (char)80, 80 }, { (char)81, 81 }, { (char)82, 82 }, { (char)83, 83 }, { (char)84, 84 }, { (char)85, 85 }, { (char)86, 86 }, { (char)87, 87 }, { (char)88, 88 }, { (char)89, 89 }, { (char)90, 90 }, { (char)91, 91 }, { (char)92, 92 }, { (char)93, 93 }, { (char)94, 94 }, { (char)95, 95 }, { (char)96, 96 }, { (char)97, 97 }, { (char)98, 98 }, { (char)99, 99 }, { (char)100, 100 }, { (char)101, 101 }, { (char)102, 102 }, { (char)103, 103 }, { (char)104, 104 }, { (char)105, 105 }, { (char)106, 106 }, { (char)107, 107 }, { (char)108, 108 }, { (char)109, 109 }, { (char)110, 110 }, { (char)111, 111 }, { (char)112, 112 }, { (char)113, 113 }, { (char)114, 114 }, { (char)115, 115 }, { (char)116, 116 }, { (char)117, 117 }, { (char)118, 118 }, { (char)119, 119 }, { (char)120, 120 }, { (char)121, 121 }, { (char)122, 122 }, { (char)123, 123 }, { (char)124, 124 }, { (char)125, 125 }, { (char)126, 126 }, { (char)127, 127 }, { (char)128, 128 }, { (char)129, 129 }, { (char)130, 130 }, { (char)131, 131 }, { (char)132, 132 }, { (char)133, 133 }, { (char)134, 134 }, { (char)135, 135 }, { (char)136, 136 }, { (char)137, 137 }, { (char)138, 138 }, { (char)139, 139 }, { (char)140, 140 }, { (char)141, 141 }, { (char)142, 142 }, { (char)143, 143 }, { (char)144, 144 }, { (char)145, 145 }, { (char)146, 146 }, { (char)147, 147 }, { (char)148, 148 }, { (char)149, 149 }, { (char)150, 150 }, { (char)151, 151 }, { (char)152, 152 }, { (char)153, 153 }, { (char)154, 154 }, { (char)155, 155 }, { (char)156, 156 }, { (char)157, 157 }, { (char)158, 158 }, { (char)159, 159 }, { (char)160, 160 }, { (char)260, 161 }, { (char)728, 162 }, { (char)321, 163 }, { (char)164, 164 }, { (char)317, 165 }, { (char)346, 166 }, { (char)167, 167 }, { (char)168, 168 }, { (char)352, 169 }, { (char)350, 170 }, { (char)356, 171 }, { (char)377, 172 }, { (char)173, 173 }, { (char)381, 174 }, { (char)379, 175 }, { (char)176, 176 }, { (char)261, 177 }, { (char)731, 178 }, { (char)322, 179 }, { (char)180, 180 }, { (char)318, 181 }, { (char)347, 182 }, { (char)711, 183 }, { (char)184, 184 }, { (char)353, 185 }, { (char)351, 186 }, { (char)357, 187 }, { (char)378, 188 }, { (char)733, 189 }, { (char)382, 190 }, { (char)380, 191 }, { (char)340, 192 }, { (char)193, 193 }, { (char)194, 194 }, { (char)258, 195 }, { (char)196, 196 }, { (char)313, 197 }, { (char)262, 198 }, { (char)199, 199 }, { (char)268, 200 }, { (char)201, 201 }, { (char)280, 202 }, { (char)203, 203 }, { (char)282, 204 }, { (char)205, 205 }, { (char)206, 206 }, { (char)270, 207 }, { (char)272, 208 }, { (char)323, 209 }, { (char)327, 210 }, { (char)211, 211 }, { (char)212, 212 }, { (char)336, 213 }, { (char)214, 214 }, { (char)215, 215 }, { (char)344, 216 }, { (char)366, 217 }, { (char)218, 218 }, { (char)368, 219 }, { (char)220, 220 }, { (char)221, 221 }, { (char)354, 222 }, { (char)223, 223 }, { (char)341, 224 }, { (char)225, 225 }, { (char)226, 226 }, { (char)259, 227 }, { (char)228, 228 }, { (char)314, 229 }, { (char)263, 230 }, { (char)231, 231 }, { (char)269, 232 }, { (char)233, 233 }, { (char)281, 234 }, { (char)235, 235 }, { (char)283, 236 }, { (char)237, 237 }, { (char)238, 238 }, { (char)271, 239 }, { (char)273, 240 }, { (char)324, 241 }, { (char)328, 242 }, { (char)243, 243 }, { (char)244, 244 }, { (char)337, 245 }, { (char)246, 246 }, { (char)247, 247 }, { (char)345, 248 }, { (char)367, 249 }, { (char)250, 250 }, { (char)369, 251 }, { (char)252, 252 }, { (char)253, 253 }, { (char)355, 254 }, { (char)729, 255 } }; #endregion }

Błąd MediaElement AG_E_NETWORK_ERROR w Windows Phone

Podczas używania MediaElement i testowaniu aplikacji na urządzeniu sporadycznie możemy dostać błąd AG_E_NETWORK_ERROR na evencie MediaFailed.

Aby temu zapobiec trzeba wykonać następujące kroki:

  1. podłącz telefon do komputera
  2. zamknij Zune
  3. uruchom linie komend (cmd)
  4. nawiguj do C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.0\Tools\WPConnect
  5. uruchom wpconnect.exe i gotowe a błąd już się nie pojawi

Tilt Shift na Windows Phone

Kolejny program mojego autorstwa dostępny w sklepie Zune.

Tym razem program do symulacji efektu tilt-shift. Przyda się każdemu kto lubi robić zdjęcia smartfonem i chce im nadać niepowtarzalny wygląd. Program w obsłudze jest banalnie prosty a pozwala na uzyskanie ciekawego efektu jakby się fotografowało miniaturowy świat.

Program można kupić tutaj w cenie 0.99$.

Poniżej screeny z aplikacji oraz film z użytkowania.

Ready for take-off?

Na oficjalnym blogu The Windows Phone Developer Blog od jakiegoś czasu pojawiają się bardzo ciekawe porady o tworzeniu oprogramowania na telefony Windows Phone. Polecam każdemu, kto zajmuje się tematem na poważnie albo dopiero ma zamiar zacząć przygodę :)

Aktualnie dostępne są części od 1 do 5:

  1. Start tiles and splash screens are your first impression? Make them great.
  2. Make sure your buttons are visible even when the keyboard is displayed.
  3. Managing themes on WP7. Or how to build your application to respect system color changes.
  4. Make sure your finger can hit the target and text is legible.
  5. Give feedback on touch and progress within your UI.

Tip Calculator na Windows Phone

Od jakiegoś czasu w sklepie Zune można kupić mój pierwszy program na Windows Phone. Jest to prosty kalkulator napiwków.

Więc jeśli masz problem z przeliczaniem napiwków albo poszedłeś do restauracji ze znajomymi i nie potraficie obliczyć rachunku, to na pewno ten drobny programik Ci się przyda. A wszystko w cenie 0.99$.

Poniżej screeny z aplikacji oraz film z użytkowania.

“Programming Windows Phone 7″

Dziś na blogu Microsoft Press pojawiła się darmowa książka “Programming Windows Phone 7″, którą można bezpośrednio pobrać tutaj.

Jeszcze nie zdążyłem jej przeczytać, ale po oględnym spojrzeniu na wybrane rozdziały już mogę powiedzieć, że naprawdę warto. Książka w bardzo praktyczny sposób podchodzi do programowania Silverlight i XNA na telefony, zawierając bardzo dużo rozwiązań typowych problemów związanych z developerką na nowe urządzenia.




Windows Phone 7 fail

Nie lubię angielskich tytułów, ale nie potrafiłem znaleźć lepiej pasującego odpowiednika w języku polskim – może przez moją ułomność językową. Ale nie o tym miało być.

Wszyscy już chyba wiedzą, że Microsoft udostępnił wersję RTM dla Windows Phone. Wszystko wygląda pięknie. Zasób materiałów, tutoriali, blogów, pod-castów i czego tam sobie jeszcze nie wymyślimy jest porażający. To co się nie zmieściło w standardowych kontrolkach udostępniono jako Toolkit dla Windows Phone. Wciąż mało? No to dorzucę jeszcze kontrolkę reklamową dla telefonu. Teraz już chyba starczy. Czyż nie wygląda to pięknie? Ja przez dwa dni miałem na oczach bielmo podekscytowany taką ilością materiałów!

Ale Windows Phone 7 nie odniesie sukcesu i już tłumaczę dlaczego:

  • Brak natywnych aplikacji. O ile na początku myślałem, że to fajny pomysł to już wiem że jest wprost przeciwnie. Aplikacjom Silverlight daleko jest do wydajności iOS. Oczywiście proste listy lub gry w XNA będzie trudno porównać do Objective-C; o tyle w SL przy pomocy C# nigdy nie napiszemy aplikacji przetwarzającej obrazy w czasie rzeczywistym.
  • Brak załączników w e-mailach. Aktualne klasy SL dla Windows Phone nie pozwalają na wysyłanie poczty z załącznikiem. Brakuje także wsparcia dla MMS – już można się śmiać.
  • Brak wsparcia dla kamery z prawdziwego zdarzenia. Obsługa kamery w obecnych klasach opiera się na klasie CameraTask, która pozwala na zrobienie zdjęcia… i tyle. Nie doczekamy się aplikacji Augmented Reality ani zwykłego czytnika kodów paskowych na WP7, bo Microsoft postanowił nie publikować API do klas, które istnieją – bo były już we wczesnej becie.
  • Brak wsparcia dla kodu niezabezpieczonego. Windows Phone nie pozwala na użycie dyrektywy unsafe a więc pożegnajmy wszystkie zoptymalizowane metody pod względem szybkości przetwarzania.

Ilość niedociągnięć jest porażająca. Obawiam się że Windows Phone 7 w oczach twórców ma być odrobinę bardziej inteligentnym dump phone-m i zdaje mi się, że nie wyciągnęli wniosków z upadku KIN-a.

Przedłużyłem o rok subskrypcję w Marketplace aby się przekonać na własnej skórze ile mam racji; w końcu suma 325 zł nie jest aż tak kosmiczna. A może się zdarzyć tak, że pojawi się spora grupa odbiorców, których nie będzie interesować Augmented Reality a będą potrzebowali gier casual lub prostych programów do obliczania wydatków dziennych.

Windows Phone 7 Series – kolejna porcja złych wieści

Jeżeli wydawało ci się, że horror się skończyły to mam dla ciebie złych wiadomości ciąg dalszy:

  • Brak natywnych odwołań. Zapomnij że istnieje DllImport. Żadna aplikacja wykorzystująca natywne odwołania nie przejdzie certyfikacji Marketplace. A jak wiesz w WP7S jest to jedyna metoda dystrybucji oprogramowania. Niby nic a jednak. Microsoft ma predyspozycje do ukrywania pewnych fajnych funkcji w swoich bibliotekach i często tylko DllImport pozwalał na ich wydobycie i używanie w aplikacjach. Kolejna sprawa to bluetooth, który obecnie tylko da się obsługiwać przez natywne odwołania. XNA nie wspiera grania po BT a więc jak sobie Microsoft wyobraża grę po sieci skoro …
  • Brak socketów. Tak nie przesłyszałeś się. SL ani XNA nie wspiera jakichkolwiek działań po sieci. A notyfikację są do tego zbyt wolne. Odwołania HTTP będą działać bo na nich opiera się sieć w Silverlight ale nic poza tym. Nie napiszesz alternatywnego programu do obsługi poczty; FTP-a ani czatu.
  • Nie dość, że nie ma multitaskingu, to nie będziesz miał kontroli na tym kiedy twoja aplikacja jest uruchamiana albo zamykana.  A więc zapomnij o evencie OnClosing – nie uda ci się oszukać systemu. Po zadanym czasie twoja aplikacja zostanie automatycznie zabita.
  • Brak SQL CE. To już zaczyna być śmieszne. Ale Windows Phone 7 Series nie posiada obsługi SQL-a. Nie przechowasz żadnych danych lokalnie, no chyba że na plikach XML w isolated storage (sic!) albo jakimś innym silnikiem bazy np SQL Lite.

Jaka wizja WP7S wynika z tych wszystkich ograniczeń? Otóż Microsoft ma wizję telefonu, który jest bardzo cienką końcówką zdarzeń w chmurze. Jeżeli piszesz aplikację biznesową na telefon nie obędzie się bez serwisu w chmurze. Czyli dodatkowych kosztów, bo ktoś będzie musiał zapłacić za development i hosting.

W idealnym świecie mamy cały czas dostęp do internetu, który jest za darmo. Ale ja mieszkam w Polsce i nie dość że dużo płacę za internet na komórce to jeszcze dobry zasięg kończy się wraz z tablicą miasta. Wizja telefonu giganta jest ciekawa, ale dlaczego ogranicza możliwości, które zawsze były dostępne w ich telefonach?

Windows Phone 7 Series – File Explorer

A propos ostatnich rewelacji o braku File Explorer-a w Windows Phone 7 Series – mała próba pobrania plików i katalogów z głównego katalogu telefonu.

Snippet użyty w screencaście:

try
{
    foreach (string s in System.IO.Directory.GetFiles(@"\"))
        Debug.WriteLine("File: " + s);
}
catch (Exception ex) { }

try
{
    foreach (string s in System.IO.Directory.GetDirectories(@"\"))
        Debug.WriteLine("Directory: " + s);
}
catch (Exception ex) { }

MIX10 i Windows Phone 7 Series – moje wrażenia

MIX10 oficjalnie się zakończył. Właściwie powiedziano już wszystko i znam odpowiedzi na prawie wszystkie nurtujące mnie pytania. Postaram się w skrócie podsumować to wszystko co powiedziano na MIX-ie oraz dodać kilka swoich przemyśleń.

A więc po kolei.

Po pierwsze udostępniono Windows Phone Developer Tools CTP, które zawiera:

  • Visual Studio 2010 Express for Windows Phone CTP
  • Windows Phone Emulator CTP
  • Silverlight for Windows Phone CTP
  • XNA 4.0 Game Studio CTP

Wbrew pozorom ta informacja niesie ze sobą podprogowy przekaz :) Otóż na 99% możemy się spodziewać Visual Studio 2010 Express w wersji dla deweloperów Windows Phone. Co jest rewelacyjną informacją dla osób, które do tej pory nie mogły sobie pozwolić na “pełną” wersję Visual Studio (Express nie wspiera pisania aplikacji pod WM). A więc prawie na pewno przybędzie chętnych do spróbowania swoich sił.

Po drugie sam nowy system operacyjny jest dość kontrowersyjny:

  • nie obsługuje multitaskingu a więc aplikację nie będą mogły chodzić w tle
  • nie ma opcji kopiuj / wklej – Microsoft tłumaczy się zaawansowanym systemem rozpoznawania informacji na ekranie (np. numerów telefonu). Ale nijak nie potrafię sobie wyobrazić sytuacji kiedy chcę przekleić np kawałek tekstu strony internetowej i wrzucić to na Blipa.
  • nie ma kart pamięci – jakoś nie wyobrażam sobie sytuacji gdzie ładuje do pamięci Auto Mapę , która ma 1GB danych i trzymam to non  stop w telefonie
  • nie masz dostępu do plików – nie żebym był jakiś strasznym fanem tego rozwiązania ale nie wyobrażam sobie sytuacji gdzie nie mogę ręcznie posprzątać plików w pamięci a pisząc programy telefon można zaśmiecić bardzo szybko

Po trzecie zmiany dotkną Marketplace:

Zostaną usunięte ograniczenia geograficzne. W końcu! Jakbym miał jeszcze raz w życiu wrzucić Tangram Pro osiem razy w języku angielskim tylko dlatego, że to inny kraj to chyba bym sobie darował.

Po czwarte – zajmijmy się konkretami:

Zestaw nowych bibliotek .NET dla Windows Phone 7 Series jest w wersji 4.0 – oczywiście mowa o podstawowym zestawie. A więc tu bez zmian – Microsoft zachował się tak jak przy poprzednich wersjach i udostępnił prawie identyczne zestawy.

Poza nim dostajemy zestaw bibliotek XNA w namespace Microsoft.XNA. Muszę przyznać, że odrobinę bawiłem się XNA na emulatorze i wyniki są naprawdę genialne. W tym się naprawdę bardzo prosto pisze gry. Koniec ze sztuczkami graficznymi  GDI. Dostajemy prawdziwe narzędzie do pisania gier.

Plus zestaw silverlight z namespace Microsoft.Phone.Controls. Tutaj nie ma rewelacji. Oczywiście CTP nie jest wersją ostateczną, ale aktualny zestaw kontrolek nie powala. Brakuje mi wielu rzeczy i mam nadzieję, że to się zmieni. Co jest ciekawe w Application.Resources dostajemy domyślny zestaw styli telefonu a więc odpada nam karkołomna sztuka ustalania standardu. Na pewno zyskają na tym interfejsy i iPhone z Androidem mogą się zacząć bać, choćby z tego powodu że SL na telefonie wspiera IIS Smooth Streaming, DRM i tym podobne “dobra”.

API telefonu dostępne jest w bibliotekach Microsoft.Device. Obecnie widać akcelerometr i wibrację. Na pewno jest jeszcze obsługa kamery z dostępem do “czystych” klatek oraz kompas.

Kolejna ciekawostka. Dodano bibliotekę Microsoft.Phone.License która zawiera w sobie jedyną klasę License a w niej metodę IsTrial(). Marketplace otrzyma możliwość udostępniania aplikacji w wersji trial i wtedy powinniśmy sprawdzić wartość tej metody. Zastanawia mnie tylko jak się Microsoft zabezpieczył się przed podmianą tej biblioteki na taką która zawsze będzie zwracać false.

Na zakończenie otrzymaliśmy Microsoft.Phone.Notification do obsługi notyfikacji oraz Microsoft.Phone.Tasks która ma obsługiwać odpalanie map Bing, okna kamery, przeglądarki internetowej oraz odpowiada za obsługę pseudo funkcji wklej, bo na przykład pozwala zapisać adres email klasą SaveEmailAddressTask.

Na marginesie nie ma bibliotek System.Windows tak jak wcześniej zapowiadano a więc nie ma klasy Clipboard do obsługi schowka.

A tych wszystkich, których zastanawia brak File Explorera w telefonie przy jednoczesnym istnieniu biblioteki System.IO czeka niemiła niespodzianka. Ale to już sprawdźcie sami :)

Podsumowując

Nawiązując do jednego ze swoich poprzednich postów Windows Phone 7 Series – lista życzeń programisty spełniły się dwa z moich trzech życzeń. SL jest w wersji 4. Za Expression Blend będę musiał w Polsce zapłacić pewnie z 2 tysiące złotych (pomijajjąc fakt, że u nas jest on dużo droższy niż np w USA) oraz system posiada API do kamery, akcelerometru i kompasu. Myślę, że to niezły wynik.

W jakich kolorach maluje się przyszłość power userów? W tym momencie trudno odpowiedzieć na to pytanie. Jeżeli jesteś “kucharzem” ROM-ów i zapalonym tweakerem to zapewne porzucisz Windows Mobile i przerzucisz się na Androida.
A co do deweloperów – na odpowiedź musimy zaczekać do pierwszych wyników sprzedaży telefonów z Windows Mobile 7. Jeżeli się okaże, że telefony sprzedają się rewelacyjnie to nic tylko pisać aplikację i zarabiać kasę. Jeżeli jednak okaże się, że Microsoft się pomylił to nie pozostanie nam nic jak tylko przerzucić się na Androida / iPhone-a.