目次

WPF開発

WPFとは

Windows Presentation Foundation(WPF)は、マイクロソフトが開発したグラフィカルユーザーインターフェース(GUI)を開発するためのグラフィックスサブシステムの名称である。.NET Framework 3.0に含まれてリリースされた。
WPFでは、XAML(Extensible Application Markup Language)と呼ばれるXMLベースの描画用マークアップ言語に対応している。従来のビットマップグラフィックスの他にベクタグラフィックスを扱うことが可能であり、3次元グラフィックスや動画なども容易に扱えるようになった。これらのユーザーインターフェースは、テキストやドキュメントも含めて、統一的なAPIを用いて開発することができる。

WPFの最大の売りは多彩なUIによるユーザー体験の豊かさである。

Windows Formsとの違い

メリット

Windows Formsと比べてWPFのいいところは可変のレイアウトが作りやすいこと。
また、色々なデバイスでできるだけレイアウトが崩れないようにフォントサイズを含めたすべてのサイズ指定で論理ピクセル座標が標準になっている。参照:デバイス非依存ピクセル(DIU)について

Windows Forms では主に UI 要素に対してプロパティーを通じて個別に外観設定を行いますが、WPF では異なるスタイリングに対するアプローチをとっています。
WPF では強力なスタイルモデルを提供しており、基本的には Web 開発で用いられる CSS のような手法でスタイリングが行われます。これにより一元的な外観管理を行いやすくなります。UI とロジック部分が分離されるのでアプリケーション開発者とデザイナの分業が可能です。デザイン部分の再利用性も高まり、仕様変更にも柔軟に対応すること ができます。

デメリット

WinFormに使い慣れている人からするとWPF+XAMLの習得コストが高い。
.NET Framework 4.7では、WPFの特徴でもある高DPIサポートがWindows Formsアプリケーションに適用されるようになった。但し、.NET Framework 4.7を利用してアプリケーションを開発するには、Windows 10 バージョン1703や「Visual Studio 2017」でv15.0からv15.1へのアップデートが必要。

Tips

Wrap対応のLabel

通常のLabelコントロールは、自動改行のwrapに対応していません。下記コードで対応する。

test.xaml
<Label x:Name="lblHeader" Grid.Row="0" FontSize="32" >
    <AccessText TextWrapping="Wrap" Text="手直し品です。ご注意ください。12345678901234567890"/>
</Label>

TextBlockとLabelの違い

TextBlockは文字列のみを表示することができます。一方でLabelの方はContentに与えられる全てのオブジェクトに対応することができます。
TextBlockとLabelの違い

一つの文字列に複数のデータをバインディングしたい場合

マルチバインディングを使う。
[WPF] XAMLでの文字列のフォーマット指定とバインディング

<TextBlock>
    <TextBlock.Text>
        <MultiBinding StringFormat="{}First {0} : Second {1}">
            <Binding Path="FirstValue"/>
            <Binding Path="SecondValue"/>
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

バインディングするデータが最初に来る場合は、頭に {} を付ける必要があります。(属性値のBindingなどではなく文字として中括弧がつかいたいため)

スクロールバーのサイズ取得

ListViewのスクロールバーのサイズを取得する。
wpf : ListViewのある列の幅を自動でいっぱいに広げその他の列幅は固定

var listBoxChrome = VisualTreeHelper.GetChild(listView, 0) as FrameworkElement;
var scrollViewer = VisualTreeHelper.GetChild(listBoxChrome, 0) as ScrollViewer;
var scrollBar = scrollViewer.Template.FindName("PART_VerticalScrollBar", scrollViewer) as ScrollBar;
var w = scrollBar.ActualWidth;

タスクトレイ常駐アプリ

C# WPFでタスクトレイ常駐アプリの開発

ファイル監視で画面表示

ファイル監視イベントで画面表示処理を呼び出すと「呼び出しスレッドは、多数の UI コンポーネントが必要としているため、STA である必要があります。」が発生する。
wpf - 多くのUIコンポーネントがこれを必要とするため、呼び出しスレッドはSTAでなければなりません

UIスレッドで動作させために、下記内で画面表示処理を呼び出す。

Application.Current.Dispatcher.Invoke((Action)delegate
sample
private void watcher_Changed(Object source, FileSystemEventArgs e)
{
    switch (e.ChangeType)
    {
        case WatcherChangeTypes.Changed:
        case WatcherChangeTypes.Created:
            Application.Current.Dispatcher.Invoke((Action)delegate {
                MainWindowShow();
            });
            break;
    }
}

画面表示時の例外エラー

例外エラー「'Window が閉じた後で、Visibility の設定や、Show、ShowDialog、およびWindowInteropHelper.EnsureHandl の呼び出しを行うことはできません。」

フォームインスタンスを再利用するとでる。

対応方法

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    e.Cancel = true;
    this.Visibility = Visibility.Hidden;
}

Shownイベント

WPFにはWindowが最初に表示されたときのShownイベントが無いので、代わりにContentRenderedイベントを利用する。
WPF Windowが最初に表示されたときに処理を行いたい

表示文字幅の取得

画面に表示される文字の幅を取得する。
WPFで表示文字幅の取得を行う。

sample
Typeface typeface = new Typeface(txtTest.FontFamily, txtTest.FontStyle, txtTest.FontWeight, txtTest.FontStretch);
double len = MeasureString("テスト", txtTest.FontSize, typeface).Width;
 
/// <summary>
/// 表示文字幅を取得する
/// </summary>
/// <param name="text"></param>
/// <param name="fontSize"></param>
/// <param name="typeFace"></param>
/// <returns>表示文字サイズ</returns>
private Size MeasureString(string text, double fontSize, Typeface typeface)
{
    var ft = new FormattedText(text, System.Globalization.CultureInfo.CurrentCulture,
                               FlowDirection.LeftToRight,
                               typeface, fontSize, Brushes.White);
 
    return new Size(ft.Width, ft.Height);
}

Buttonのクリックイベントを発生させる

WPFには、Windows FormにあったPerformClickメソッドが存在しない。
IInvokeProviderインターフェースを利用するには、参照の追加の参照マネージャーのアセンブリから「UIAutomationProvider.dll」を参照する。
ボタンをプログラム側からクリックする
Buttonのクリックイベントを発生させる

最大化を禁止させる

sample
//最小化ボタンは有効、最大化ボタンは表示されてるけど、無効。
this.ResizeMode = ResizeMode.CanMinimize;

WPFでGUIアプリケーションを作成する際のメモ その3

Bindingのソースが更新されない

ViewModelにINotifyPropertyChangedインターフェイスを実装する必要がある。

INotifyPropertyChangedを実装はイケてないので、ReactivePropertyを使用する。
NuGetから「ReactiveProperty 3.6.0」で入手する。

ListViewの選択背景色を変更する

XAMLでの変更方法

Change selection-color of WPF ListViewItem

<ListView.ItemContainerStyle>
    <Style TargetType="{x:Type ListViewItem}">
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Background" Value="midnightblue" />
            </Trigger>
        </Style.Triggers>
    </Style>
</ListView.ItemContainerStyle>

コードによる変更方法

WPF: How to create Styles in code/and magical Content

// 選択時の背景色
Style styleListViewItem = new Style(typeof(ListViewItem));
Trigger triggerIsMouseOver = new Trigger { Property = ListViewItem.IsMouseOverProperty, Value = true };
triggerIsMouseOver.Setters.Add(new Setter(ListViewItem.BackgroundProperty, Brash.Gold)) SolidColorBrush(selectbackColor)));
styleListViewItem.Triggers.Add(triggerIsMouseOver);
lstRework.ItemContainerStyle = styleListViewItem;

メモ