コントロールを拡張し、独自の ICommand を実装する

一般的には ICommand は Button に最初から実装されているものを使えば問題ないです。
しかし、コントロールを拡張し、ICommand のプロパティを持たないコントロールや、既に持っているコントロールでも更に追加することができます。
任意のコントロールから継承した派生クラスで、DependencyProperty で ICommand のプロパティを追加すれば OK です。

■ コントロールにプロパティを追加 ■

    class MyTextBox:TextBox
    {
        public ICommand LostFocusCommand {
            get { return (ICommand)GetValue(LostFocusCommandProperty); }
            set { SetValue(LostFocusCommandProperty,value); }
        }

        private static readonly DependencyProperty LostFocusCommandProperty
            = DependencyProperty.Register(
                nameof(LostFocusCommand), typeof(ICommand), typeof(MyTextBox)
                , new PropertyMetadata(null) );

        public MyTextBox()
        {
            this.LostFocus += (sender, e) => {
                LostFocusCommand?.Execute(null);
            };
        }
    }

■ ViewModel の設定 ■

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = new Model();
        }
    }

    public class Model{

        class ShowMessageCommandImpl : ICommand
        {
            public event EventHandler CanExecuteChanged;

            public bool CanExecute(object parameter) { return true; }

            public void Execute(object parameter) { MessageBox.Show("LostFocus"); }
        }

        public ICommand ShowMessageCommand { get; } = new ShowMessageCommandImpl();
    }

■ 画面に上記のコントロールを定義 ■

<local:MyTextBox VerticalAlignment="Top" LostFocusCommand="{Binding ShowMessageCommand}"/>

上記のサンプルを実行すると、TextBox の LostFocus 時に ICommand を介して MessageBox を表示するメソッドが起動します。

広告

XAML の UI デバッグツールを無効にする

VisualStudio 2015 UPDATE 2 がやってきたので早速導入してみました。
アップデート後、試しに WPF アプリをデバッグ実行してみると、デバッグ中のアプリの中にデバッグ用のツールボックスが表示されるようになりました。
この画像のウィンドウの上端真ん中の黒い部分です。

20160402_01

「ライブ ビジュアル ツリーに移動」
「選択を有効にする」
「レイアウト ガイドを表示」
のボタンが並んでいます。

消したい場合は、

メニュー > デバッグ > オプション >
デバッグ > 全般 > XAML のUI デバッグツールを有効にする

20160402_02

で消すことができます。
このチェックを変えても、表示が変わらない場合はリビルドしてみると変わるかもしれません。

UWP で日本語縦書きをしてみる Part 1

UWP は現状縦書きに対応していません。
そこでなるべく簡単に縦書きをしてみることにしました。
戦略としては、縦並びのリスト表示コントロールを右から左へ並べ、文字列は文字のリストにして表示してみようと思います。

UWP の標準のフォントはプロポーショナルフォントなのでそのまま縦に並べると真っすぐに並びません。
そこでまず、リスト表示の内部の中央寄せのスタイルを作ります。
アイテムの並べ方とアイテムの表示テンプレートのスタイルをリソースにします。
<Page.Resources>
    <Style x:Key="TateStyle" TargetType="ItemsControl">
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Vertical"/>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemTemplate">
             <Setter.Value>
                 <DataTemplate>
                     <Grid Width="14" Height="18">
                         <TextBlock Text="{Binding}" HorizontalAlignment="Center"/>
                    </Grid>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Page.Resources>

続いて画面上に表示するコントロールです。
StackPanel で Orientation=”Horizontal” を指定し横向きに並べます。
それだけだと、左から右に並んでしまうので、FlowDirection=”RightToLeft” を指定し右から左に並ぶようにします。
<StackPanel Orientation="Horizontal" FlowDirection="RightToLeft">
    <ItemsControl ItemsSource="{Binding ViewBody1, Mode=OneWay}"  Style="{StaticResource TateStyle}"/>
    <ItemsControl ItemsSource="{Binding ViewBody2, Mode=OneWay}"   Style="{StaticResource TateStyle}"/>
</StackPanel>

ビューモデルでは、縦書き表示用に文章を文字のリストのした値を公開するプロパティを用意します。
/// <summary>
/// 本文の1行の長さ
/// </summary>
internal static readonly int BODY_LENGTH = 28;
/// <summary> 本文 </summary>
private string _body = string.Empty;
/// <summary>
/// 本文
/// </summary>
public string Body { get { return _body; } set { _body = value; } }
/// <summary> 本文1 </summary>
public IEnumerable<char> ViewBody1 => this._body?.ToCharArray().Skip(BODY_LENGTH * 0).Take(BODY_LENGTH);
/// <summary> 本文2 </summary>
public IEnumerable<char> ViewBody2 => this._body?.ToCharArray().Skip(BODY_LENGTH * 1).Take(BODY_LENGTH);

これでひとまず、文字が縦向きに並びます。
しかし、これでは句読点などが横書き用なので、左下になってしまいます。縦書きなら右上になってほしいところです。
が、その話は Part2 で。

UWP で中断/再開の処理をデバッグする

UWP アプリでデバッグ時に中断/再開の処理をデバッグできずに困りました。
実機デバッグでは中断/再開がおきず、デバッグでなく Mobile 単体で動作させると中断/再開がおきる、という状態。
で、検索をしてみると次の “雪猫ノート” さんの記事が見つかり、無事解決しました。

([UWP] アプリの中断や再開をデバッグする http://blog.snowcait.info/2015/12/29/uwp-debug-suspend-resume/

Mobile で UWP アプリ実行時にステータスバーが見えなくなってしまう問題について

Visual Studio で UWP プロジェクトを新規作成しそのまま Mobile で起動すると、Mobile のステータスバーが見えなくなってしまうことがあります。
※ Mobile:Windows 10 Mobile 端末
※ ステータスバー:スマートフォン上部のアンテナピクトやバッテリー残量、現在時刻が表示れている領域

■ 発生条件
・端末の色テーマ(白/黒の選択)が黒。
・UWP アプリの RequestedTheme が Light。(新規作成時のデフォルト)
もしくは
・端末の色テーマ(白/黒の選択)が白。
・UWP アプリの RequestedTheme が Dark。

OS のバグなんじゃ、という気もします。

■ 現象の解説
1.アプリ実行時のステータスバーの前景色が、端末のテーマにより固定。
2.アプリ実行時のステータスバーの背景色が、アプリのテーマに入り固定。
のため
3.端末のテーマとアプリのテーマが異なる場合、前景色と背景色が同色になってしまう。
ということが起こっています。

■ 実験
実際に端末のテーマとアプリのテーマの組み合わせでどう表示されるか確認してみましょう。

・端末:黒、アプリ:Light(前景色が白、背景色が白)

20151220_001

・端末:白、アプリ:Light(前景色が黒、背景色が白)

20151220_002

・端末:白、アプリ:Dark(前景色が黒、背景色が黒)

20151220_003

・端末:黒、アプリ:Dark(前景色が白、背景色が黒)

20151220_004
■ 解決案
アプリのテーマを指定している以上、端末の設定によって必ず見えなくなるパターンがあります。
2分の1です。分の悪い賭けですね。
ならば、アプリのテーマを指定しない。そういうのもあります。
GUI のプロパティ ウィンドウからでは、指定を消せないので、App.xaml を手で編集して Delete キーでぽちっと消してみます。

・端末:黒、アプリ:-(前景色が白、背景色が端末テーマの黒)

20151220_005

・端末:白、アプリ:-(前景色が黒、背景色が端末テーマの白)

20151220_006

■ でもテーマを指定したい!
アプリのテーマでなくページ単位にテーマを指定します。
アプリのテーマと違って全ページに指定しなければならないのでもれが怖いですが。
まぁ、中華フォント対策にすべてのページに言語設定をもれなく追加し続けてきた歴戦の Windows Phone アプリ開発者なら問題ないでしょう。

・端末:白、アプリ:-、ページ:Light(前景色が黒、背景色が端末テーマの白、アプリの領域のテーマが白)

20151220_007

・端末:白、アプリ:-、ページ:Dark(前景色が黒、背景色が端末テーマの白、アプリの領域のテーマが黒)

20151220_008

■ 解決策その2。ステータスバーの背景色を設定する
アプリのテーマを削除することはスマートな解決策ですが、問題もあります。
GUI のプロパティ ウィンドウで触ってしまうと、また消すのに App.xaml 設定が生まれてしまうことがあります。
入念に注意しておけば大丈夫かもしれませんが、複数人で開発する場合など、意図せず設定を生んでしまうことがあるでしょう。
そこで、プランステータスバー B です。プラン B はステータスバーの背景色に色を固定でつけてしまうというものです。
前景色が白でも黒でも視認性の良い背景色を設定してしまえば、OK です。
ステータスバーの背景色は、Page の Background で設定できるようです。

・端末:白、ページの背景色:Red(前景色が黒、背景色が赤、アプリの領域のテーマが白)

20151220_009

ここで気になる点が。Page の Background ではアプリの領域の背景色が変わっていませんね。
では、アプリの領域の背景色は何処で変えるのでしょうか?
Page 直下の Grid の Background を設定してみます。

・端末:白、ページの背景色:Red、Grid の背景色:Blue(前景色が黒、背景色が赤、アプリ領域の背景が青)

20151220_010
ひとまずこれで、ステータスバーが視認できるようになりました。
これで時間を気にしながら、没頭できる SNS クライアントも作れますね!