≒ 【未解決】UWP(C++/CX)アプリでのダブルタップイベント不具合

結局解決できなかったので後日改めてのための覚え書き。ヘッダファイルとか諸々は省略&コード内容も大分簡略化。
(一応動くように出来たので最後に追記しました。でもおまじないみたいな実装で、とても「解決」と言えるレベルのものではないのでタイトルはそのままw)
[code language=”cpp”]
void MyApp::MainPage::OnDoubleTapped(Platform::Object^ sender, Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs^ e){
e->Handled = true;

// Windows::Foundation::Collections::IVector<MyClass^>^ classesがあって、それを操作する処理
//各MyClassはMainPage.xaml内でGridやその中のRelativePanel、TextBlockとx:Bindで繋げてある。
change_classes();

Update_bindings();
}

void MyApp::MainPage::Update_bindings()
{
try
{
if (this != nullptr &&this->Bindings != nullptr) {
this->Bindings->Update();
}

}
catch (Platform::Exception^ e)
{
OutPrintln(e->Message, true);
}
}

void MyApp::MainPage::OutPrintln(Platform::String ^ s, Platform::Boolean flg)
{
Platform::String^ tmp = s;
if (flg) {
tmp = tmp + L"\r\n";
}
OutputDebugString(tmp->Data());
}
[/code]
で、ダブルタップすると落ちる。
「ハンドルされない例外が 0x023CE76B (Windows.UI.Xaml.dll) で発生しました(MyApp.exe 内): 0xC000041D: ユーザー コールバック中に未処理の例外が発生しました。。 」
「。」が二つあるのも気になるけど、とにかく落ちる。
メッセージが「例外がスローされました:読み取りアクセス違反。**this** が nullptr でした。 が発生しました」って時もあって、UWPが未だに良く分かってない俺にはどうしようもない。
IVectorへのアクセスミスかなと思ってそこ見直しても違いは無い。何が原因か突き止めるのに一日。
[code language=”cpp”]
void MyApp::MainPage::OnDoubleTapped(Platform::Object^ sender, Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs^ e){
e->Handled = true;
change_classes();

//Update_bindings();
}
[/code]
コメントアウトすると大丈夫。更に変だと思ったので
[code language=”cpp”]
void MyApp::MainPage::OnDoubleTapped(Platform::Object^ sender, Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs^ e){
e->Handled = true;
change_classes();

OutPrintln("AAA", true);
Update_bindings();
OutPrintln("CCC", true);
}

void MyApp::MainPage::Update_bindings()
{
OutPrintln("BBB", true);
try
{
if (this != nullptr &&this->Bindings != nullptr) {
this->Bindings->Update();
}

}
catch (Platform::Exception^ e)
{
OutPrintln(e->Message, true);
}
}
[/code]
として走らせると、
[code language=”bash”]
AAA
BBB
CCC
[/code]
と出力してから落ちる。
ダブルタップで発生する処理は、ドラッグ&ドロップでも発生する処理なので、少し手直ししてメソッドを共通化してもダブルタップだけ落ちる。
そもそも落ちるときにソースの表示がされないで「automaticdraghelper.cppが見つかりません」と出る。なお「automaticdraghelper」でググると珍しく「automaticdraghelper に一致する情報は見つかりませんでした。」とでる。ほんとにUWPは情報少ない。
「呼び出し履歴」ってウィンドウを見ると全然俺のコードとは関係ないところで落ちてるようだし、今回はあきらめてこのタップイベント拾うのやめるか(他の部分でのダブルタップ実装は何の問題もない)と考えて、コードを削る前最後に単純にOnDoubleTappedのまま(DoubleTappedRoutedEventArgsのまま)、シングルタップイベントに付け替えたらちゃんと動く。あきれたーw 要はUWPのダブルタップイベントの不具合は俺には突き止められないことが今回は分かった。
その後はシングルタップイベントハンドラを工夫して「疑似ダブルタップ」みたいなこともやろうとして、Windows::UI::Xaml::DispatcherTimerとか仕込んで、いざ動作確認!って走らせたらなんか変。すごく長い間隔の2回タップは当然「2回のシングルタップ」として認識して、ちょっと早めの(いわゆるダブルタップより微妙に長い間隔の)2回タップを「ダブルタップ」として認識する。そしてすごく早い2回タップ(いわゆるダブルタップ)は全部「1回のシングルタップ」になっちゃう。何で? 要するにシングルタップイベントの発生にはインターバルが必要なのか。なるほどねー。というオチも付いたということで、今回は以上。

[20時追記]
MSのフォーラムに情報あり。UWPアプリにはダブルタップで処理が2回走ってエラーになる場合があるらしい。この例とは違うんだけど、同じダブルタップということで処理の途中にインターバル入れてみる。
[code language=”cpp”]
//我ながらページのコンストラクタでタイマーの設定やるのもどうかと思う。定石はOnNavigatedToでやるみたい。
MainPage::MainPage()
{
InitializeComponent();
mTimer = ref new Windows::UI::Xaml::DispatcherTimer();
TimeSpan span;
span.Duration = (1LL * 1000000000) / 1000;//1/10秒
mTimer->Interval = span;
mTimer->Tick += ref new Windows::Foundation::EventHandler<Platform::Object ^>(this, &MyApp::MainPage::mTimer_OnTick);
}

void MyApp::MainPage::OnDoubleTapped(Platform::Object^ sender, Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs^ e){
e->Handled = true;
mTimer->Start();
}

void MyApp::MainPage::mTimer_OnTick(Platform::Object ^sender, Platform::Object ^args)
{
mTimer->Stop();
change_classes();
Update_bindings();
}
[/code]
ダブルタップされてから1/10秒後に処理をするようにしただけ。これで落ちなくなった。なんか馬鹿々々しいな。今度こそ以上。

≒ jawiki/latest 20170220/ のページ数の件>2143336

また5000ちょっとレコード増加。Wikipediaさんは相変わらず順調。

俺のほうもイマイチ優れない体調除けば順調。でもコーディングの進捗は牛歩。ほんとC++/CXの情報の少なさはコピペプログラマには辛すぎる。
面白いのはstackoverflowやMSのフォーラムでもUWP関連のドキュメントの整備具合はあんまり評判が良くないように見受けられること。
やっぱり思うことは一緒だよなー。サンプル通り打ち込んでも動かないと何を信じればいいのかわからなくなっちゃう。
先日もAPIドキュメントに例として載ってたコードを打ち込んだ結果、
[code language=”cpp”]
void OnDrop(Platform::Object^ sender, Windows::UI::Xaml::DragEventArgs^ e)
{
Platform::String^ aaa = safe_cast<Platform::String^> (e->Data->GetView()->Properties->Lookup("aaa"));
OutputDebugString((aaa + L"\r\n")->Data());
}
[/code]
落ちる。例そのまま、何も余計なことしていないのに落ちる。なおその例の載ってたドキュメントがどこだったかは失念。
というかドキュメントの更新頻度はすごく早いので2~3日前の状況と違うことがよくある。頑張ってくださってるのは間違いない。
で、数時間試行錯誤して結局サンプルを読むと違う書き方してるのでそれに倣ってみる。
[code language=”cpp”]
void OnDrop(Platform::Object^ sender, Windows::UI::Xaml::DragEventArgs^ e)
{
Platform::String^ aaa = safe_cast<Platform::String^> (e->DataView->Properties->Lookup("aaa"));
OutputDebugString((aaa + L"\r\n")->Data());
}
[/code]
問題なく動く。あの例は何だったんだということがあった。うーん。Javaで書いてる(コピペしてる)時と比べると一手間多い感じ。
まぁ俺のコーディング能力の無さが一番でかいんだけどね。

≒ jawiki/latest 20170201/ のページ数の件>2137499

今回2回もデータ更新スキップしちゃった。スキップしたのは20170101と20170120。

年末から体調が優れず、けど仕事は休めず、UWP開発(ってほどのレベルに達してないけど)はやりたい、で他のことに手が出なかった。
でもC++/CXが大分楽しくなってきた。でもまぁUWPアプリやってる分にはマネージドの範囲でしかC++触ってないんだから、ポインターとかメモリ管理とか全く分かってないんだけど。
今やってるアプリが終わったら一度素のC++を勉強してみようと思ってる。けど他にも作りたいものあるし、思ってるだけになる予感もするw