SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

「ペライチ」からはじめよう
~C++/CX Windows 8.1ストアアプリことはじめ

step3:Button-clickをバインドする

 つぎに「ふやす/へらす」Buttonのクリックに反応せにゃなりません。各ButtonはそれぞれIncrement/Decrementプロパティにバインドしてあるので、この2つをCounterViewModelに用意します。Command="{Binding ~}"でバインドされるプロパティの型:Windows::UI::Xaml::Input::ICommandを実装した、小さいながらとっても便利なクラス:RellayCommandがCommonディレクトリに作られているので有り難く使わせていただきましょう。

CounterViewModel.h
#pragma once

#include "Common/RelayCommand.h"
#include "CounterLib/CounterLib.h"

namespace CounterApp {

    namespace cx {
      namespace xaml  = Windows::UI::Xaml;
      namespace data  = Windows::UI::Xaml::Data;
      namespace input = Windows::UI::Xaml::Input;
    }

    [Windows::UI::Xaml::Data::Bindable]
    public ref class CounterViewModel sealed : cx::data::INotifyPropertyChanged{
    public:
        CounterViewModel();

        virtual event cx::data::PropertyChangedEventHandler^ PropertyChanged;
        property int Count { int get(); }

        property cx::input::ICommand^ Increment  { cx::input::ICommand^ get(); }
        property cx::input::ICommand^ Decrement  { cx::input::ICommand^ get(); }

    private:
      void do_inc();
      void do_dec();
      void execute(std::function<void(void)> action);

        void RaisePropertyChanged(Platform::String^ propertyName);
        CounterLib::Counter counter_;
    };

CounterViewModel.cpp
#include "pch.h"
#include "CounterViewModel.h"

using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Data;

namespace CounterApp {

    auto returnsTrue = [](Object^) { return true; };

    CounterViewModel::CounterViewModel() { }

    // property Count
    int  CounterViewModel::Count::get() { return counter_.get(); }

    // property Increment/Decrement
    ICommand^ CounterViewModel::Increment::get() {
        return ref new Common::RelayCommand(returnsTrue, [this](Object^) { do_inc(); }); 
    }

    ICommand^ CounterViewModel::Decrement::get() {
        return ref new Common::RelayCommand(returnsTrue, [this](Object^) { do_dec(); });
    }

    // increment/decrement counter
    void CounterViewModel::do_inc() { execute([this]() { counter_.increment(); }); } 
    void CounterViewModel::do_dec() { execute([this]() { counter_.decrement(); }); }

    // actionを実行し、カウント値に変化があれば PropertyChanged する
    void CounterViewModel::execute(std::function<void(void)> action) {
        int prev = counter_.get();
        action();
        if ( prev != counter_.get() ) {
            RaisePropertyChanged(L"Count");
        }
    }

    void CounterViewModel::RaisePropertyChanged(String^ propertyName) {
        PropertyChanged(this, ref new PropertyChangedEventArgs(propertyName));
    }
}

 Common::RellayCommandのコンストラクタに与える引数は2つ。

 1つめはそのコマンドが実行可ならtrueを返す関数オブジェクト、ここでは常にtrueを返すラムダ式を使っています。これがfalseを返すとコマンドの発行元(ここではButton)がDisableになります。

 2つめがコマンドに応じた処理を行う関数オブジェクトです。この中でCounterのincrement()/decrement()を行い、カウント値に変化があったならRaisePropertyChanged(L"Count")して「プロパティ:Countに変化があった」ことをViewに知らせます。Viewはその知らせを受けてCountプロパティの値を読み取り、画面に反映させます。これでCounterAppの完成です。

step4:おまけ:定周期動作

 ついでにもう一つ、ゲームなどで使われることの多いタイマーによる定周期動作の実装。コレ、そんなに難しくありません。DispatcherTimerを1つ作り、インターバル(周期)とタイムアウト時の処理を与えておけば、あとはStart()/Stop()するだけです。おためしにPainPageに開始/停止Buttonを追加しDispatcherTimerを動かしてみました。開始/停止ButtonのCommandはどちらもプロパティ:Timerにバインドし、CommandParameterでどちらが押されたのかを判別しています。

MainPage.xaml(抜粋)
      <!-- このGridの中にコントロールを配置します -->
      <TextBlock Text="{Binding Count}" .../>
      <Button Command="{Binding Increment}"  Content="ふやす" .../>
      <Button Command="{Binding Decrement}"  Content="へらす" .../>
      <!-- Timerの開始/停止Buttonを追加 -->
      <Button Command="{Binding Timer}" CommandParameter="Start" Content="かってにふやす" .../>
      <Button Command="{Binding Timer}" CommandParameter="Stop"  Content="ふやすのやめ"   .../>
CounterViewModel.h
#pragma once

#include "Common/RelayCommand.h"
#include "CounterLib/CounterLib.h"

namespace CounterApp {
    ...

    [Windows::UI::Xaml::Data::Bindable]
    public ref class CounterViewModel sealed : cx::data::INotifyPropertyChanged{
    public:
    ...

        property cx::input::ICommand^ Timer { cx::input::ICommand^ get(); }

    private:
    ...

        cx::xaml::DispatcherTimer^ timer_;
        Common::RelayCommand^ cmdtimer_;
        CounterLib::Counter counter_;    
    };

}
CounterViewModel.cpp
    ...
    CounterViewModel::CounterViewModel() {
        // タイマー初期化
        timer_ = ref new DispatcherTimer();
        TimeSpan span;
        span.Duration = 100 * 1000 * 10; // 10 nano-sec / unit
        timer_->Interval = span;
        timer_->Tick += ref new EventHandler<Object^>([this](Object^,Object^){ do_inc(); });

        // タイマー開始/停止コマンド
        cmdtimer_ = ref new Common::RelayCommand(
                        [this](Object^ param) { 
                            String^ cmd = safe_cast<String^>(param);
                            if ( cmd == L"Start" )     return !timer_->IsEnabled; 
                            else if ( cmd == L"Stop" ) return timer_->IsEnabled;
                            else return false; 
                        },
                        [this](Object^ param) {
                            String^ cmd = safe_cast<String^>(param);
                            if ( cmd == L"Start" ) timer_->Start();
                            else if (cmd == L"Stop") timer_->Stop();
                            else return;
                            cmdtimer_->RaiseCanExecuteChanged();
                        });
    }

    ICommand^ CounterViewModel::Timer::get() { return cmdtimer_; }
    ...

 以上、『C++/CXでのWindows 8.1ストアアプリのつくりかた』でした。本格的なアプリにはまだ遠くおよびませんけども、はじめの一歩半は踏み出せたんじゃないでしょか。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
特集記事連載記事一覧

もっと読む

この記事の著者

επιστημη(エピステーメー)

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/7506 2013/12/17 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー