tor4kichi / Hohoema

Windows10向けニコニコ動画プレイヤー
GNU General Public License v3.0
77 stars 10 forks source link

【0.14.11】動画プレイヤーで"小さく最前面"表示できない #718

Closed tor4kichi closed 5 years ago

tor4kichi commented 6 years ago

症状

コンパクトオーバーレイを押すとハングアップする

対処方法

コンパクトオーバーレイ表示の利用を避けてください

原因

0.14.10以前に小窓表示時にUIコントロールが表示されてしまう問題への対応から波及して問題が起きています。 小窓プレイヤーでのUI非表示対応とコンパクトオーバーレイ表示のUI状態管理が競合してハングアップします。

開発の対応

UI状態管理の競合を解消する。

tor4kichi commented 6 years ago

概要

WindowsCommunityToolkitのScrollHeaderを利用したページかつページナビゲーションキャッシュを有効にしたページであるとき、当該ページがキャッシュスタックに積まれた状態でCompactOverlayModeを有効にするなど、ScrollHeaderのUpdateScrollHeaderBehavior メソッドが呼び出されることで 後述の例外が発生する模様です。

(問題発見当初の段階で)わかっている範囲でのエラー原因

おおまかな原因としてはPage.NavigationCacheMode="Enabled"を利用したページがページキャッシュスタックに残っている場合に、CompactOverlayModeを有効にすると、Xamlが生成したコード内でエラーが発生していました。

NavigationCacheMode="Disable"に変更することで問題の回避には成功しましたが、根本的な発生原因は突き止められていません。

例外のメッセージは以下の通りです(デバッグログ上でも途中でメッセージが途切れています)

System.ArgumentOutOfRangeException: Index must be within the bounds of the List.
Parameter name: index
   at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
   at System.Collections.Generic.List`1.Insert(Int32 index, T item)
   at Microsoft.Xaml.Interactivity.BehaviorCollection.BehaviorCollection_VectorChanged(IObservableVector`1 sender, IVectorChangedEventArgs eventArgs)
   at System.Runtime.InteropServices.WindowsRuntime.IVector`1.Append(T v

エラーの発生状況について

NavigationCacheMode="Enabled"に指定されたページがキャッシュスタックに積まれた状態でCompactOverlayModeを有効にすることで当エラーが発生します。

一方で、NavigationCacheMode="Enabled"に指定したページを最初に表示してCompactOverlayModeを有効にしても当エラーは発生しませんでした。

Microsoft.Toolkit.Uwp.UI.Controls.ScrollHeaderが怪しい?

検索キーワード "BehaviorCollection.BehaviorCollection_VectorChanged" の結果にある

ScrollHeader - BehaviorCollection_VectorChanged - ArgumentOutOfRangeException #1146

が状況と似ていたため、以下の条件で再度検証しました

この条件ではCompactOverlayModeを有効にしてもハングアップする問題が起きず、正常動作しました。

根本原因の推察

前述のエラーメッセージと上記検証から、BehaviorCollectionの変更が不正なタイミングで行われたことがハングアップの原因であると思われます。

そこでScrollHeaderのコードを参照してみると

https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/3b5a1f480d65c649a1732a8b8a11866ed3c08836/Microsoft.Toolkit.Uwp.UI.Controls/ScrollHeader/ScrollHeader.cs

private void UpdateScrollHeaderBehavior()
        {
            var targetListViewBase = this.FindAscendant<Windows.UI.Xaml.Controls.ListViewBase>();

            if (targetListViewBase == null)
            {
                return;
            }

            // Remove previous behaviors
            foreach (var behavior in Interaction.GetBehaviors(targetListViewBase))
            {
                if (behavior is FadeHeaderBehavior || behavior is QuickReturnHeaderBehavior || behavior is StickyHeaderBehavior)
                {
                    Interaction.GetBehaviors(targetListViewBase).Remove(behavior);
                }
            }

            switch (Mode)
            {
                case ScrollHeaderMode.None:
                    break;
                case ScrollHeaderMode.QuickReturn:
                    Interaction.GetBehaviors(targetListViewBase).Add(new QuickReturnHeaderBehavior());
                    break;
                case ScrollHeaderMode.Sticky:
                    Interaction.GetBehaviors(targetListViewBase).Add(new StickyHeaderBehavior());
                    break;
                case ScrollHeaderMode.Fade:
                    Interaction.GetBehaviors(targetListViewBase).Add(new FadeHeaderBehavior());
                    break;
            }
        }
    }

Interaction.GetBehaviors(targetListViewBase).Remove(behavior); などの操作をページがキャッシュスタック上に退避された状態で行うことが例外の発生原因と思われます。

tor4kichi commented 6 years ago

上記方法を元に最小サンプルを作成しようとしましたが、状況再現できませんでした。

上記の説明や対処はHohoemaプロジェクトにおける限定的なものとしてお考え下さい…。

状況再現できなかったものですが、作成したサンプルプロジェクトは以下になります。

ScrollHeaderBehaviorCollectionChangeIssue.zip - reproduct failed