WPFでWindows Runtime API の Windows.winmd について
WPFでWindows 8、8.1、10 のAPIを呼ぶことができます。
デスクトップ アプリからのWinRT API利用 | ++C++; // 未確認飛行 C ブログ
WPFのプロジェクトで Windows.winmd を参照するとライブラリとして使えるようになります。
WPF などの .NET Framework のアプリから UWP の API を呼ぶ - かずきのBlog@hatena
WPFアプリ(.Net Framework)でUWPのAPIを使う - Qiita
Windows SDKのインストール場所は C:\Program Files (x86)\Windows Kits\ になります。
Windows 8、8.1 はいいのですが、Windows 10 になるとメジャーアップデート毎にSDKのバージョンが違うため気をつける必要があります。
(ここからの部分を書きたいだけ)
Windows 10 のSDKをインストールすると C:\Program Files (x86)\Windows Kits\10\ にインストールされます。
Windows 10 SDK (10.0.10240) ~ (10.0.15063.468) (1507~1703)では Windows.winmd が同じ場所にインストールされてしまうので注意です。
最後にインストールしたSDKの Windows.winmd が上書きされるようで、
Windows.winmd の違いはファイルの見た目では分からないので、どのバージョンのファイルか分からなくなります。
Windows 10 SDK (10.0.16299.91) (1709) からそれぞれのバージョンでフォルダ分けされるようになったのでこの問題は解決しています。
(ここまで)
まあ、Win10のサポート期間があるので、サポート対象のバージョンを使えばよさそうです。
ついでに、、、
特定のバージョンしか対応していませんが、NuGet から追加できるようになったようです。
こっちを使ったほうが簡単ですね。
.NET のプロジェクトから WinRT API を呼ぶのが凄く簡単になってます - かずきのBlog@hatena
MSDN コードギャラリーの提供終了
MSDN コードギャラリーのページが無くなり、新しいコードサンプルページが作成されています。
https://code.msdn.microsoft.com/
MSDN コード ギャラリーの提供終了 | Microsoft Docs
新しいコードサンプルページ
Browse code samples | Microsoft Docs
悲しいことに参考になるサンプルのリンクが消滅している状態です。
- 10 行でズバリ !! シリーズ
- 連載! とことん シリーズ
などなど
今までのページはGitHubに保存されているので、この中から探しましょう!
Microsoft Archive · GitHub
https://github.com/microsoftarchive/msdn-code-gallery-community-0-9-non-alphabetic
https://github.com/microsoftarchive/msdn-code-gallery-microsoft
https://github.com/microsoftarchive/msdn-code-gallery-community-a-c
https://github.com/microsoftarchive/msdn-code-gallery-community-d-l
https://github.com/microsoftarchive/msdn-code-gallery-community-m-r
https://github.com/microsoftarchive/msdn-code-gallery-community-s-z
[WPF] Expression Blend ライブラリのいらない言語リソースファイルたち
Expression Blend の Behavior 便利ですよね!
すっごいよく使います。
System.Windows.Interactivity.dll Microsoft.Expression.Interactions.dll
Visual Studioから使うExpression BlendのBehavior達 - かずきのBlog@hatena
参照設定で追加してー
ビルドするとー
なにこれいらない・・・
こんな感じの謎のフォルダーができちゃいます。
de en es fr it ja ko ru zh-Hans zh-Hant
理由は簡単 System.Windows.Interactivity.dll、Microsoft.Expression.Interactions.dll の言語リソース用のファイルです。
皆さん大体こう思いますね。
日本語しか使わないんだけど!?
ていうかいらないんだけど!?
削除したり、そもそもコピーされないようにしたりすることで回避しているようです。
[C#] ビルド後イベントで不要なxmlや言語フォルダを削除する - ざこノート
c# - When compiling WPF application language folders are copied to build folder - Stack Overflow
コピーされないようにする
大本から削除してコピーされないようにするパターンを紹介します。
コピー元になるファイルたちは以下の場所にインストールされます。
.netのバージョンによって v4.0 と v4.5 があるようです。
C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\.NETFramework\v4.0\Libraries C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\.NETFramework\v4.5\Libraries
削除するのは戻せなくなるので、新しいフォルダに移動させていまいました。
これでビルド時に不要な言語ファイルがコピーされなくなります。
特にエラーも発生しないのでおすすめです。
Visual Studio Version Selector がぶっ壊れた
Visual Studioのソリューションファイル.slnはVisual Studio Version Selectorが関連付けられています。
Visual Studio Version Selectorは.slnファイル内に記載されているVisual Studioのバージョンを読み取り、適切なVisual Studioのバージョンを起動します。
調子が悪いとこんな画面が開きます
選択も何も、空っぽなんですが!?
OKを押しても反応がなく、キャンセルを押すと「開けませんでした。」とエラーウインドウが出る始末
新しいバージョンのVisual Studioをインストールしようとしたらこうなりました。。。
原因はVisual Studioの変更や更新が途中で止まっていることのようで、
Visual Studio Installer で止まっている変更や更新を進めたら正しくVisual Studioが起動しました。
最悪は修復すれば直るようです?
参考:
How do I add versions to “Visual Studio Version Selector”, my list is empty - Stack Overflow
ExceptionのHResultについて
C#でファイル操作などのWindowsに関わる操作を行うと内部的にはWindows APIが呼ばれます。
WindowsAPIはC#ではないので、エラーになったときにはC++的な形でエラーコードを返します。
それをC#でラッピングしてあるので、C#でExceptionとしてエラーを取得する事ができます。
C#のExceptionのメッセージだと大まかな分け方しかしていないので詳細に知りたい場合はHResultの値を調べます。
try{ }catch(Exception e ){ e.HResult // <- こいつについての話 }
例えばファイルを置換に失敗した場合 IOException になります。
try{ System.IO.File.Replace(sourceFileName, destFileName, null); }catch( IOException e ){ // e.Message → 置換されるファイルを削除できません。 // e.HResult → -2147023721 }
int型の表示でマイナスの値が表示されますが、所詮ビットデータなので2進数表示で確認します。
更に上位下位として半分ずつにします。
2進数:1000000000000111 0000010010010111 16進数:0x8007 0x0497
で、これがなんなんだっていうと 上位の0x8007はWin32エラーコードということを示しています。
下位の0x0497がエラーの番号です。
ERROR_UNABLE_TO_REMOVE_REPLACED 1175 (0x497)
置換されたファイルを削除できませんでした。置換されるファイルと置換ファイルの名前は、元のまま変更されていません。
ReplaceFileA function | Microsoft Docs
こんな感じでWindows APIのエラーコードにたどり着くことができます。
無理やりワンライナー
こんな感じのときってあると思います。
var result = ""; if( 条件1 ){ result = "1つ目"; }else if( 条件2 ){ result = "2つ目"; }
この初期化めんどくさくない?
var result = "";
メソッド
メソッドに切り出したいけど、メソッド名考えるの大変なんだよなー
var result = GetResult( 条件 ); string GetResult( 条件 ){ if( 条件1 ){ return "1つ目"; }else if( 条件2 ){ return "2つ目"; } return ""; }
匿名メソッド&即実行
Func
var result = ( (Func<string>)( () => { return "1"; }) )();
または
var result = ( new Func<string>( ()=>{ return "2"; }) )();
()括弧多すぎ問題
そしてStaticへ・・・
そしてこうなった・・・
var result = Func.Run( ()=>{ return "1"; } ); public static class Func { public static T Run<T>( Func<T> func ) { return func(); } }
他の便利な使い方
初期化のときにメソッドの形で書けます。
public class Item { public string Value { get; set; } = Func.Run( () => { return ""; } ); }
初期化のときにメソッドの形で書けます。その2
var item = new Item(){ Value = Func.Run( () => { return ""; } ), }
[Rx] 変更通知の合成はObservable.Merge<object>です。
WPFでBindingする時にLivetを使っていたのですが、ReactivePropertyが面白そうだったのではじめました。
Livetだと自分の好きなタイミングで変更通知イベントを出せていたのですが、Rxだとそのタイミングもロジックとして書く必要があります。
要は、AプロパティとBプロパティのどちらかが変わった時に、Cプロパティの変更通知を出したい みたいな
Livet
Livet で書くとこんな感じ
public class LivetViewModel : ViewModel { public int A { get => _A; set { if( _A != value ){ _A = value; this.RaisePropertyChanged(); this.RaisePropertyChanged( nameof(this.C) ); } } } int _A; public int B { get => _B; set { if( _B != value ){ _B = value; this.RaisePropertyChanged(); this.RaisePropertyChanged( nameof(this.C) ); } } } int _B; // A, B が変わった時にCの値が変わる public int C => A + B; }
ReactiveProperty
だいたいCombineLatestを使えと書いてあるのでこんな感じ
public class RxViewModel { public RxViewModel() { this.C = this.A.CombineLatest(this.B, (a,b)=> a+b).ToReactiveProperty(); } public ReactiveProperty<int> A { get; } = new ReactiveProperty<int>(); public ReactiveProperty<int> B { get; } = new ReactiveProperty<int>(); public ReactiveProperty<int> C { get; } }
ReadOnlyとかSlimとかしっかり使うとこんな感じ
public class RxViewModel2 { public RxViewModel2() { this.C = this.A.CombineLatest(this.B, (a,b)=> a+b).ToReadOnlyReactivePropertySlim(); } public ReactivePropertySlim<int> A { get; } = new ReactivePropertySlim<int>(); public ReactivePropertySlim<int> B { get; } = new ReactivePropertySlim<int>(); public ReadOnlyReactivePropertySlim<int> C { get; } }
ただし、CombineLatest だと全ての値がそろわないと通知が始まらないので「値がない場合~」とかはできません。
やっと本題 Observable.Merge<object> を使いましょう。
public class RxMerge { public RxMerge() { this.C = Observable.Merge( this.A, this.B ) .Select(x => this.A.Value + this.B.Value ).ToReadOnlyReactivePropertySlim(); } public ReactivePropertySlim<int> A { get; } = new ReactivePropertySlim<int>(); public ReactivePropertySlim<int> B { get; } = new ReactivePropertySlim<int>(); public ReadOnlyReactivePropertySlim<int> C { get; } }
CombineLatest の謎のラムダ式 (a,b)=> a+b も消えてスッキリしました。
全ての型が同じ場合は型推論でジェネリックの<T>部分を書かなくていいですが、複数の型が混ざる場合は<object>とすれば問題ありません。
そしてそして、本当にやりたかったことは ReactiveCommand のコマンドが実行可能かどうかという CanExecute 部分の書き方なのだった・・・
Observable.Merge<object>( // 変更通知 が来たら条件判定したいReactiveProperty this.A, this.B ).Select( x => { // True になる条件 return this.A.Value != 0 && this.B.Value != 0; } ) .ToReactiveCommand()
複数の条件が複雑に混ざり合うような時にとても重宝します。
追記 2018/10/18
ジェネリックのキャストの都合上IObservable<[struct]>がIObservable<object>にキャストできないので無理やり変換します。
こんなの用意して
public static Observable { public static IObservable<object> Cast<T>( this IObservable<T> source ) where T: struct { return source.Select( x => (object)x ); } }
こうだ!
public class RxMerge { public RxMerge() { this.C = Observable.Merge( this.A.Cast(), this.B ) .Select(x => this.A.Value + int.Parse( this.B.Value ) ).ToReadOnlyReactivePropertySlim(); } public ReactivePropertySlim<int> NumItem { get; } = new ReactivePropertySlim<int>(); public ReactivePropertySlim<string> StrItem { get; } = new ReactivePropertySlim<string>(); public ReadOnlyReactivePropertySlim<int> C { get; } }
2019/01/29 追記
ToUnit() で IObservable
いまさら聞けないReactive Extensions.3 - Qiita
Unit は戻り値なしのvoid的なやつだそうです。
でもデバッグ的にはIObservable<object> のほうが便利だなー
// ReactiveProperty.dll namespace Reactive.Bindings.Extensions { public static class ToUnitObservableExtensions { public static IObservable<Unit> ToUnit<T>( this IObservable<T> self ); } } // こんな感じ Observable.Merge( this.A.ToUnit(), this.B.ToUnit() )
[WPF] タッチ長押しで右クリックをやめる(□を表示させない)
少ないですがWindowsタブレット用のアプリでドラッグやタッチしっぱなしの操作がメインのときにタッチ長押しの右クリック機能が邪魔なときがあります。
対象のXamlの添付プロパティにこれを使いするだけ
Stylus.IsPressAndHoldEnabled = false
こんな感じです。
<Grid Stylus.IsPressAndHoldEnabled="False"> </Grid>
WindowsFormsではこの設定はなさそうなので珍しくWPFの利点でしょうか
参考
[C#/VB/XAML] WPF 4 における TouchDown や TouchUp など基本的なイベントを使用して、マルチタッチ対応アプリケーションを作成 in C#, VB.NET
他にもStylusクラスには面白そうなものがあるのでご覧あれ
Stylus Class (System.Windows.Input) | Microsoft Docs
[WPF] ComboBoxをItemsSourceとSelectedItemで扱う時の注意
2019/06/13 再度試してみたら問題なく初期値が設定されました
SelectedItem で初期値を設定する場合には SelectedItem を先に設定してから ItemsSource を変更しないと初期値が設定されない場合があるようです。
味気ないので、雰囲気コード(実際には動かない)置いておきます。
こんなコンボボックスを作って
<ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" DisplayMemberPath="Name" />
ViewModel部分
public class ViewModel : INotifyPropertyChanged { public List<Item> Items { get; set; } // 変更通知 public Item SelectedItem { get; set; } // 変更通知 public void ChangeComboBox(){ // これだとダメ //this.Items = new List<Item>(){ // new Item(){ Name = "1" }, // new Item(){ Name = "2" }, // new Item(){ Name = "3" }, // }; //this.SelectedItem = this.Items.First(); var items = new List<Item>(){ new Item(){ Name = "1" }, new Item(){ Name = "2" }, new Item(){ Name = "3" }, }; this.SelectedItem = items.First(); this.Items = items; } } public class Item { public string Name { get; set; } public int Value { get; set; } }
[WPF] ワンランク上のPOPUP コントロール
POPUP コントロール についてです。
よく 「ボタンを押す」→「ポップアップ出す」というデザインを使います。
ポップアップの動作的にはこんな感じになると思います。
- ボタンを押す。
- ポップアップを表示させる。
- ポップアップ以外の場所をクリックするとポップアップが閉じる。
ただね、
- ボタンを押す。
- ポップアップを表示させる。
- ボタンをクリックする。
- ボタンを押す時のMouseDownでポップアップが閉じる。
MouseUPでポップアップが表示される。
ポップアップ閉じてくれえええええ
はい。
すっごい探しまして見つけました。
ToggleButton のNameを指定しないといけませんが、仕方ないでしょう。
<Grid> <ToggleButton Name="tbWithPopup" Width="30" Height="30" IsChecked="{Binding ElementName=pUp, Path=IsOpen}"> <ToggleButton.Style> <Style TargetType="ToggleButton"> <Style.Triggers> <DataTrigger Binding="{Binding ElementName=pUp, Path=IsOpen}" Value="True"> <Setter Property="IsHitTestVisible" Value="False" /> </DataTrigger> </Style.Triggers> </Style> </ToggleButton.Style> <Polygon Points="0,0 2,0, 1,1" Fill="Black" Stretch="Fill" /> </ToggleButton> <Popup Name="pUp" PlacementTarget="{Binding ElementName=tbWithPopup}" AllowsTransparency="True" StaysOpen="False" Width="200"> <RichTextBox IsReadOnly="True"> <RichTextBox.Document> <FlowDocument> <Paragraph> Checkout WPF Tat for more elegant solutions </Paragraph> </FlowDocument> </RichTextBox.Document> </RichTextBox> </Popup> </Grid>
この人神様かな?
WPF TaT: ToggleButton with Popup
Visual Studio デザインモードの判定
Visual Studioのデザイナーすごい便利ですよね!
ただ、デザイン時には実行してほしくないコードが実行されてしまうときもあります。
そんなときはコードに実行中かどうかの判定を記述しましょう。
自分は以下のコードを使用しています。
if( System.ComponentModel.LicenseManager.UsageMode != System.ComponentModel.LicenseUsageMode.Runtime ) { //ここはデザイン時にしか通らない }
他にも判定方法はあるようです。
.net - DesignMode with nested Controls - Stack Overflow
[WPF] 自作ライブラリを使う時に、Xamlのxmlnsで指定する名前空間について
自分でライブラリを作った時にXmlnsDefinitionを記述するとXamlで指定する名前空間に好きな文字を付けられます。
AssemblyInfo.cs にでも記述しておくとわかりやすいかな?
// [assembly: XmlnsDefinition("Xamlでの名前空間", "ライブラリのネームスペース")] // 複数のnamespaceを同じ名前にしてもOK [assembly: XmlnsDefinition("http://schemas.WpfApp1/", "WpfApp1")] [assembly: XmlnsDefinition("http://schemas.WpfApp1/", "WpfApp1.View")]
使うときは指定した名前空間を使用します。
xmlns:wpfApp1="http://schemas.WpfApp1/"
名前空間の指定に決まりはなく、好きな名前が付けられるようです。
// これも行ける? [assembly: XmlnsDefinition("俺のライブラリ", "WpfApp1")]
参考:
[WPF] WPF入門 ~XAML編 [名前空間]~
XAMLの基礎(1/2) - @IT
2009-09-27 - 当面C#と.NETな記録
[WinForm] NativeWindowでWinProcの処理を切り分け
WinFormの場合、WinProcからメッセージを受け取って処理を行うという処理をまとめたい場合にNativeWindowと便利になります。
といっても下記URLからの情報なのでこれ以上は無いです😭
マウスのホイールをコロコロした時にマウスオーバー(エンター?)しているコントロールのスクロールバーを動かしたい
C# マウスホバー状態のコントロールにホイールでスクロールさせる – Try&Error テクニカルブログ
[WPF] WebBrowserコントロール
WebBrowserコントロールを使用すると、アプリケーション内でブラウザを使用することができます。
が、これはMicrosoftのコントロールなのでInternet Explorerです。
しかも、互換性の問題とやらで標準ではIE7になります。
最新のIEを使用するためにはレジストリに値を追加する必要があります。
さらに、タッチ機能も無効になっているので有効にする必要があります。
さらに、ローカルのファイルを読み込むとセキュリティ警告が出るので、ローカルのファイル読み込みを有効にします。
void SetIEBrowserLatest() { var filename = Assembly.GetEntryAssembly().ManifestModule.Name; // WebbrowserのIEバージョンを指定 using( var key = Registry.CurrentUser.CreateSubKey( @"SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION" ) ) { key.SetValue( filename, 11001, RegistryValueKind.DWord ); } // ローカルのファイル読み込みを有効にする using( var key = Registry.CurrentUser.CreateSubKey( @"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BLOCK_LMZ_SCRIPT" ) ) { key.SetValue( filename, 0, RegistryValueKind.DWord ); } // タッチ機能を有効にする using( var key = Registry.CurrentUser.CreateSubKey( @"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_NINPUT_LEGACYMODE" ) ) { key.SetValue( filename, 0, RegistryValueKind.DWord ); } }
タッチ機能を有効にしないと、ライブラリによってはJavascriptのイベントが走らずに動かないものがあります。
例えばこのライブラリ
image.py — Bokeh 0.12.14 documentation
参考:
scroll - C# WebBrowser PanningMode - Stack Overflow
また別の問題もあるようですが・・・
Windows 8のWebBrowserControlをタッチ対応にする - kkamegawa's weblog
WPFのデザインについて
WPFではView(デザイン)の変更がわりと簡単に行えるが、少し特殊なことをしたいときにはどうにもならない場合がある。
ControlTemplateを使った場合、指定したデザインに固定されてしまうため、Windowsのバージョンによって微妙に違うコントロールのデザインが違う部分が全く吸収できないのである。
さらに言えば、VisualStudioで「テンプレートの編集」→「コピーして編集」をした時のテンプレートが開発環境のOSに依存する。
Win7でこの作業を行うと、Win8で表示した時にWin7のデザインで表示されるわけです。
では、どうするかというと、上記サイトのようにテーマごとに地道にコードを書くしか無い感じです。
こういうところがWinFormに劣っている気がします。