1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C++/WinRTでUWPその4 データバインディングその2 コントロールへの変更通知

Last updated at Posted at 2021-03-04

C++/WinRTでUWPその3の続きです。

#1.変更を通知するには
変更をコントロールへ通知するのに必要なのは以下の3点です。
①. idlファイルに変更を通知するよ、という宣言を入れる。
②. hファイルとcppファイルにPropertyChanged()というプロパティーを実装する。
③. 変更した箇所でデータメンバからPropertyChangedEventArgsを呼び出す。

それぞれ実装していきます。

#2.変更通知箇所の実装

##2-1. StringViewModel.idlファイルの変更
・宣言に「Windows.UI.Xaml.Data.INotifyPropertyChanged」を追加します。

StringViewModel.idl(変更前)
namespace bind_1
{
    [Windows.UI.Xaml.Data.Bindable]
    runtimeclass StringViewModel 
    {
        StringViewModel();
        String DataString;
    }
}
StringViewModel.idl(変更後)
namespace bind_1
{
    [Windows.UI.Xaml.Data.Bindable]
    runtimeclass StringViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
    {
        StringViewModel();
        String DataString;
    }
}

##2-2. StringViewModel.hファイルの変更
・PropertyChangedプロパティーとm_propertyChangeメンバを追加します。

StringViewModel.h(変更前)
#pragma once

#include "StringViewModel.g.h"

namespace winrt::bind_1::implementation
{
    struct StringViewModel : StringViewModelT<StringViewModel>
    {
        //ここはdefaultを削除
        StringViewModel();
        //ここ追加
        StringViewModel(const winrt::hstring value);

        //ここ追加 セッターですね
        void DataString(winrt::hstring const& value);
        //こちらはゲッター
        winrt::hstring DataString();

    private:
        //ここ追加
        winrt::hstring m_DataString;
    };
}

namespace winrt::bind_1::factory_implementation
{
    struct StringViewModel : StringViewModelT<StringViewModel, implementation::StringViewModel>
    {
    };
}
StringViewModel.h(変更後)
#pragma once

#include "StringViewModel.g.h"

namespace winrt::bind_1::implementation
{
    struct StringViewModel : StringViewModelT<StringViewModel>
    {
        StringViewModel();

        //ここ追加
        StringViewModel(const winrt::hstring value);

        //ここ追加
        void DataString(winrt::hstring const& value);
        winrt::hstring DataString();

        //ここ追加(View Modelの変更通知)
        winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
        void PropertyChanged(winrt::event_token const& token) noexcept;

    private:
        //ここ追加
        winrt::hstring m_DataString;

        //ここ追加(View Modelの変更通知)
        winrt::event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;
    };
}

namespace winrt::bind_1::factory_implementation
{
    struct StringViewModel : StringViewModelT<StringViewModel, implementation::StringViewModel>
    {
    };
}

##2-3. StringViewModel.cppファイルの変更 ・PropertyChangedを実装して、変更を通知する箇所でm_propertyChangedを呼び出します。 ・ゲッターではm_propertyChanged.add(handler)を返すだけ、セッターではm_propertyChanged.remove(token)を設定するだけです。 ・そしてコントロールに通知したい箇所にm_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"DataString" })をいれればOK。L"DataString"でないと、DataStringで変更通知されません。一度違う文字列でも試してみて下さい。 ・DataString(winrt::hstring const& value)を呼んだ回数も表示するようにしているので、その分の蛇足も入ってます。
StringViewModel.cpp(変更前)
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"

using namespace winrt;
using namespace Windows::UI::Xaml;

namespace winrt::bind_1::implementation
{
    MainPage::MainPage()
    {
        //ここ追加
        m_SViewModel = winrt::make<bind_1::implementation::StringViewModel>();
        InitializeComponent();
    }

    int32_t MainPage::MyProperty()
    {
        throw hresult_not_implemented();
    }

    void MainPage::MyProperty(int32_t /* value */)
    {
        throw hresult_not_implemented();
    }
}

//ここ追加
bind_1::StringViewModel winrt::bind_1::implementation::MainPage::SViewModel()
{
    return m_SViewModel;
}
StringViewModel.cpp(変更後)
#include "pch.h"
#include "StringViewModel.h"
#if __has_include("StringViewModel.g.cpp")
#include "StringViewModel.g.cpp"
#endif

#include <string>
#include <sstream>
namespace winrt::bind_1::implementation
{
    static int g_Num = 0;

    //ここ以降追加
    StringViewModel::StringViewModel() : m_DataString(L"First String")
    {
    }
    StringViewModel::StringViewModel(const winrt::hstring value)
    {
        m_DataString = value;
    }

    void StringViewModel::DataString(winrt::hstring const& value)
    {
        //何回呼ばれたかも表示(蛇足部分)
        g_Num++;
        std::wstring strvalue;
        std::wostringstream woss;
        woss << g_Num;
        strvalue = value + L" " + woss.str();

        m_DataString = strvalue;

        //ここ追加(View Modelの変更通知)
        m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"DataString" });
    }
    winrt::hstring StringViewModel::DataString()
    {
        return m_DataString;
    }

    //ここ追加(View Modelの変更通知)
    winrt::event_token StringViewModel::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
    {
        return m_propertyChanged.add(handler);
    }
    //ここ追加(View Modelの変更通知)
    void StringViewModel::PropertyChanged(winrt::event_token const& token) noexcept
    {
        m_propertyChanged.remove(token);
    }
}


##2-4. MainPage.cppファイルの変更
・前回追加した、button1_Clickというイベントハンドラーにクリックされたことを追加します。ここは変更後だけ。

MainPage.cpp(変更後)
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"

using namespace winrt;
using namespace Windows::UI::Xaml;

namespace winrt::bind_1::implementation
{
    MainPage::MainPage()
    {
        //ここ追加
        m_SViewModel = winrt::make<bind_1::implementation::StringViewModel>();
        InitializeComponent();
    }

    int32_t MainPage::MyProperty()
    {
        throw hresult_not_implemented();
    }

    void MainPage::MyProperty(int32_t /* value */)
    {
        throw hresult_not_implemented();
    }
}


void winrt::bind_1::implementation::MainPage::button1_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
    //ここ追加(View Modelの変更通知)
    SViewModel().DataString(L"Clicked");
}

//ここ追加
bind_1::StringViewModel winrt::bind_1::implementation::MainPage::SViewModel()
{
    return m_SViewModel;
}


・これでビルド→実行すると、以下のようになり・・・ってクリック前は変わらないよ? ![3-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/c2a867e1-e68a-461c-6674-cbde08c058ec.png)

・クリックすると、void StringViewModel::DataString(winrt::hstring const& value)が呼ばれ、その度にコントロールへの更新通知が呼ばれるのでクリックするたびにTextBlockの文字列が変わります。下のの画像は2クリックした後です。ここまでやるとバインドのありがたみが少しは出てきますね。
3-2.png

・詳しくはINotifyPropertyChanged.PropertyChanged Eventとか前回から出ているXAML コントロール: C++/WinRT プロパティへのバインドを確認してみてください。

・さて、次はListViewへのバインドです。ListViewって何個も表示できますよね?そこを実装します。

もくじへ

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?