2012年12月30日日曜日

ゆっくりMovieMaker3 開発日記 - 44 「BindingExpression path error に伴うコンディションの低下に悩まされる」

前回からの作業内容
アイテムの矩形選択の実装
アイテム編集用コントロールのコンディションを改善


あれ?いつの間にか滅茶苦茶重くなってるぞ・・・
前々回の記事で、「アイテムの矩形選択を実装してくれ」とのコメントがあったので早速実装し、動作確認をしていた時のこと。
以前はそうでもなかったのだが、アイテムの選択にかかる時間が極端に長くなっている。
体感0.7秒程度。
我慢できないことは無いけど、微妙にストレスを感じるカクつきが生じていた。


どうやらアイテム編集用のコントロールが悪さをしているらしい
調べてみると、アイテム選択時、アイテム編集用コントロールへアイテムを渡している段階で重たくなっている。
ここでふと思い当たる節があり、VisualStudioのログ出力画面を見ると、、、、


System.Windows.Data Error: 40 : BindingExpression path error:~~~

と書かれたエラーログが50行ほど表示されていました。


こいつだ!
ログに出力されている大量の例外メッセージ。

たしか例外をキャッチするのには結構なコストがかかっていて、大量にcatchするとソフトが重たくなると、C#入門サイトに書いてあった・・・。
おそらくこいつが原因だろう。
(今までは「なんかエラーでてるけど、動いてるから無視して大丈夫だよね。」と無視してました。。。)

また、「BindingExpression path error コスト」でググってみると
[Windows] wpfアプリケーションの性能改善の記事
http://moated.wordpress.com/2011/09/23/windows-wpfアプリケーションの性能改善の記事/
BindingExpression path errorは性能劣化につながる。Databindingをデバッグせよ。
との記述が。ああ、やっぱりそうなのね。


エラーログの原因
そもそも、なぜこんな大量のエラーログを吐くに至ったのか。
まずはこの画像を見て頂きたい。
これは、アイテム編集用コントロール。
動画アイテム用・画像アイテム用・ゆっくりボイス用・音楽ファイル用・字幕用・キャラ素材用と、
全てのアイテムをこのコントロール1つで編集できます。

さて、このコントロールにアイテムを渡してやると、各種スライダーやテキストボックスなどに、アイテムのプロパティが表示されるのだが、この時動画アイテムを渡した場合でも、字幕アイテムや画像アイテム専用のプロパティにアクセスしようとして、「そんなの見つからないよ!」とエラーを吐いてくるのだ。
このエラーをキャッチするのに処理が重くなり、結果ソフトの応答性が悪くなっていた。

完全に楽をしようとして状況が悪くなったパターン。


さて、どうやってこの問題を解決すべきか。。。
一番最初に思いついたのは、アイテムの型でBindingの有効/無効が切り替えられないのかという案。
が、ググってもそれらしい物は見つからなかった。無念。

しょうが無い。ソフト側が「そんなの見つからないよ!」と言ってきているのが原因なのだから、ダミーのアイテムを渡して例外を発生させないように使用。
どうせダミーを渡した部分のコントロールは非表示にする仕様なのだから問題は無い。

ということで、DataContext用のコンバーターを作成。

public class DummyDataContextConverter : IValueConverter {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value;
            if (value == null) return null;
            switch ((string)parameter) {
                case "Voice":
                    if (value is VoiceItem == false) 
                        return new VoiceItem();
                    return value;
                case "Audio":
                    if (value is AudioItem == false) 
                        return new AudioItem();
                    return value;
                case "Image":
                    if (value is ImageItem == false) 
                        return new ImageItem();
                    return value;
                case "Video":
                    if (value is VideoItem == false)
                        return new VideoItem();
                    return value;
                case "Jimaku":
                    if (value is JimakuItem == false) 
                        return new JimakuItem();
                    return value;
                case "Face":
                    if ((value is FaceSetItem || value is VoiceItem) == false) 
                        return new FaceSetItem();
                    return value;
                case "COBase":
                    if (value is CharacterBaseItem == false){
                        var coBase = new CharacterBaseItem();
                        coBase.COBaseSetting.Initialize();
                        return coBase;
                    }
                    return value;
            }
            throw new Exception("未定義の型です");
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }


Bindingしているコントロールを含むGrid等を
<Grid  DataContext="{Binding Converter={StaticResource DummyDataContextConverter},ConverterParameter=Voice}">
としてやれば、この場合は「ゆっくりボイス」アイテムの場合はそのまま入力したアイテムを返し、「ゆっくりボイス」で無い場合はダミーのアイテムを返す。

手法としては完全に邪道なんでしょうが、これ以上の方法を見つけられなかったので今回はこれで。
この方法で改良した結果、アイテム選択時のカクつきは完全に解消されました。
よかったよかった。



0 件のコメント:

コメントを投稿