いつもどこかでデスマーチ♪

不定期に、私の日常を書き込みしていきます。

C# WPFのLoaded イベントが複数回(2回)発生する!?

2024年08月28日 16時47分56秒 | .NET系
表題の通り、Loaded イベントって普通1回しか発生しないよね?と思いながら、初期表示時に2回発生して困った話…
ただ、多分特殊なのか仕様なのか分からないので、メモのために残しておく

XAMLの内容:
1.TabControl を使う
2.TabItem を使って、AタブとBタブの2個のアイテムを作る
3.AタブとBタブは状況によってVisibility を設定し表示、非表示が切り替わる(これ関係ないかも)
4.タブの内容は別XAMLファイルに記載している(<local:ATabItem/> みたいな感じ)
5.ユーザがタブを切り替えれるが、内部処理からもタブを切り替え可能

ベースのXAML例:
<TabControl HorizontalAlignment="Stretch"
            SelectedIndex="{Binding TabSelectedIndex.Value," Mode="TwoWay," UpdateSourceTrigger="PropertyChanged}">
    <TabItem HorizontalAlignment="Center"
             Visibility="{Binding IsATabItemVisibility.Value," Converter="{StaticResource" convBooleanToVisibility}}">
        <local:ATabItem Margin="5,5,10,5"/>
    </TabItem>
    <TabItem HorizontalAlignment="Center"
             Visibility="{Binding IsBTabItemVisibility.Value," Converter="{StaticResource" convBooleanToVisibility}}">
        <local:BTabItem Margin="5,5,10,5"/>
    </TabItem>
</TabControl>


ベースのViewMode例:
internal class AnalysisMainViewModel : DisposableBindableViewModelBase, IDisposable, IDestructible
{
    public ReactiveProperty<int> TabSelectedIndex { get; set; }
    public ReactivePropertySlim<bool> IsATabItemVisibility { get; set; }
    public ReactivePropertySlim<bool> IsBTabItemVisibility { get; set; }
    public AnalysisMainViewModel()
    {
        TabSelectedIndex = new ReactiveProperty<int>(0); // ここで0個目(ATab)を選択される
        TabSelectedIndex.Subscribe(TabChangedCommand)
                        .AddTo(Disposables);
        IsATabItemVisibility = new ReactivePropertySlim<bool>(true).AddTo(Disposables);
        IsBTabItemVisibility = new ReactivePropertySlim<bool>(true).AddTo(Disposables);
    }
    
    // 何かのタイミングでATabとBTabの初期表示を切り替える
}




ATabとBTabのXAML例:
<UserControl なんかいろいろ
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             xmlns:prism="http://prismlibrary.com/"
             mc:Ignorable="d" 
             prism:ViewModelLocator.AutoWireViewModel="True">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <prism:InvokeCommandAction Command="{Binding LoadedCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <Grid>
        ATab/BTab用のなんかいろいろ
    </Grid>
</UserControl>


ATabとBTabのViewModel例:
public abstract partial class TabBaseViewModel : DisposableBindableViewModelBase, IDisposable, IDestructible
{
    public ReactiveCommand LoadedCommand { get; set; }
    public TabBaseViewModel()
    {
        LoadedCommand = new ReactiveCommand().WithSubscribe(Loaded).AddTo(Disposables);
    }
    protected virtual void Loaded()
    {
        // ATabとBTabを切り替えるごとに毎回処理が来る
        // そのため、イベント登録処理を書いておくとイベントが何個も登録されてしまう
    }
}




これの問題点:
1.初期表示時にATabとBTabの両方の Loaded イベントが発生する。
2ー1.初期表示をATabの場合:問題無い
2-2.初期表示をBTabに変更した場合:1.に加え、さらにもう1回 Loaded イベントが発生する。
3.ついでにユーザが切り替えるごとにLoadedイベントが発生してました。(要確認)

結果 BTabを初期表示させようとすると Loaded メソッドが2回走ってしまい、イベント登録(IEventAggregator へのsubscribe)が2回されてしまい、対象イベントが2回動いてしまう。
合わせて、Unsubscribe を2回呼び出さないとイベント呼び出しが残ってしまい予期せぬ不具合に発展してしまいます。

Loaded イベント/ Unloaded イベント は Tab切り替え時に毎回発生するようなので、ブレークポイントやログ出力していつ発生するかきちんと見たほうが良いと思う

という個人メモ


てか .NET Framework の頃って Loaded って1回だけじゃなかっけか?勘違い?いつから変わったんだ?


.net 6
ReactiveProperty:9.2.0
コメント    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« ReactiveProperty で TextBox... | トップ | Chat GTP(無料版) …お前って... »

コメントを投稿

ブログ作成者から承認されるまでコメントは反映されません。

.NET系」カテゴリの最新記事