Creators Updateで標準がコマンドプロンプトからPowerShellに変わったけどなんの問題もなかった件
Windows 10 Creators Updateが出てから四か月以上たって今更ではありますが、標準のCUI(スタート右クリックやエクスプローラーでShift+右クリックで選べるやつ)がコマンドプロンプトからPowerShellに変わりましたね
CUIなんてiisreset
ping
ipconfig
しか使わないからコマンドプロンプトでいいんだよ!と思って一度はコマンドプロンプトに変えたんですが、PowerShellで全部できるんですよね
ということですぐにPowerShellに戻しました
おしまい
Xamarin.iOSで時計とやり取りするあれこれ
以前
を書きましたが、あれから時が経ちました
久しぶりにいじったらいろいろ変わっていてはまったのでそんなことを
大前提
古いバージョンはストアに出さない
これさえなければはまることもなく古い奴を出しっぱなしで済んだんですけどね
watchOS 1のアプリはストアに出ません*1
ということでOS 2.0以降のプロジェクトを新規に作りました watchOSのプロジェクトは比較的小さいはずなので無理やりプロジェクトを変換するより作り直した方が速いと思います
ということで以下に書くのはwatchOS 3.2(phone側は10.3.1)を前提とします
通信方式
1.0のころ使っていた
WKInterfaceController.OpenParentApplication
は使えなくなりました
Watch Connectivityってやつを使うらしいっす
この辺を簡単にラップしたのがXamarinのページにあります
上のサンプルではUpdateApplicationContext
メソッドだけがラップされています
今回はこのメソッドではないものを使いました*2
SendMessageを使う
上記サンプルに追記して使います
送る側
public void SendMessage(NSDictionary<NSString, NSObject> sendData) { Console.WriteLine($"SendMessage on {Device}"); if (validSession == null || session.Delegate == null) return; try { validSession.SendMessage(sendData, (replyMessage) => { //応答 }, (obj) => { Console.WriteLine("Send error." + obj); }); } catch (Exception ex) { Console.WriteLine($"Exception SendMessage: {ex.Message}"); } }
一つ目の引数(NSDictionary)が送信データ、二つ目が受信側からのコールバック、三つ目がエラーのハンドラです
受ける側
public override void DidReceiveMessage(WCSession session, NSDictionary<NSString, NSObject> message) { Console.WriteLine($"Receiving Message on {Device}"); } public override void DidReceiveMessage(WCSession session, NSDictionary<NSString, NSObject> message, WCSessionReplyHandler replyHandler) { Console.WriteLine($"Receiving Message on {Device}"); replyHandler(new NSDictionary<NSString, NSObject>( new[] { (NSString)"" }, new[] { (NSObject)null }) ); }
二種類のDidReceiveMessage
をoverrideする必要があります
両方実装しないと送信側にエラーが出ます(なぜ!)
replyHandlerを呼ぶと送信側の//応答
部分が呼ばれるみたいです
制限
一度に送信できるデータサイズには制限があります
出典がどこかわかりませんがstackoverflow先生が教えてくれました
SendMessageの場合は65536byteだそうです*3
このサイズを超えたデータを送信しようとした場合・・・何も起こりません
相手に届かないだけでエラーにはなりません(はまるよ!)*4
約65KBというサイズですが、watch全体に表示する画像をPNGで送ろうとした場合、少し複雑になると超えるくらいのサイズです
透過PNGでもなければJPEGで圧縮して送りましょう(送りました)
最後に
今回の内容もちゃんと調べてませんがそもそもXamarinでwatchアプリ作っている人なんていないと思うのでてきとうでいいですよね
WPFのItemsControlで仮想化が効かない時に確認すること
なんで仮想化しないんだろー、と悩んでいたら当たり前だったこと
準備
<DataTemplate> <TextBlock Text="{Binding Converter={StaticResource TextConverter}}"/> </DataTemplate>
DataTemplateをこんな感じで書いて
public class TextConverter : IValueConverter { private int _counter; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { System.Diagnostics.Debug.WriteLine($"Convert {_counter++}"); return value; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
こんなコンバーターを作っておきました
TextBlockが作られるたびにTextConverter.Convertが呼ばれて、何回呼ばれたかが_converterで分かります
あとはコードビハインドで
private void MainWindow_Loaded(object sender, RoutedEventArgs e) { Items.ItemsSource = Enumerable.Range(0, 100); }
って書いておけばいいですね (ItemsはItemsControlの名前)
_converterの数で何個TextBlockが作られたかわかるはずです
仮想化が効くとき
<ItemsControl x:Name="Items" VirtualizingStackPanel.IsVirtualizing="True" ScrollViewer.CanContentScroll="True"> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Converter={StaticResource TextConverter}}"/> </DataTemplate> </ItemsControl.ItemTemplate> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.Template> <ControlTemplate> <ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False"> <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" /> </ScrollViewer> </ControlTemplate> </ItemsControl.Template> </ItemsControl>
TextBlockは画面に表示している分+1個くらいしか作られません
仮想化が効かないとき
<ScrollViewer> <ItemsControl x:Name="Items" VirtualizingStackPanel.IsVirtualizing="True" ScrollViewer.CanContentScroll="True"> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Converter={StaticResource TextConverter}}"/> </DataTemplate> </ItemsControl.ItemTemplate> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl> </ScrollViewer>
TextBlockは100個作られます
外のScrollViewerで隠れてはいますがItemsControlの高さが全項目分表示できる高さになっているので当たり前ですよね
こぴぺヨクナイ
なんでこんな書き方をしていたかというと、ItemsControlをスクロール可能にする方法をStackOverflowなどで調べると下の書き方が結構出てくるからなんですね
コピペはしませんが「こー書けばいいのねー」と何も考えずに書いたせいです
スミマセンデシタ