C#でタブ用WebBrowserを開発中なのですが、クラス設計、オブジェクト指向についていまいち理解できていません。  
現在TabControl、TabPage、WebBrowserコントロールを継承したコントロールを作り、  
TabControl上でList型の変数を持ちタブのドラッグ移動、追加・削除、並び順等を管理しています  
TabPage上でWebBrowseの変数を持ち、コンストラクタでurlを受け取ったりブラウザバック・フォワードを受け取り、それをwebBrowserへ渡したり、現在表示されているWebページのタイトルをWebBrowserのイベントで受け取りTabPageラベルのTextに設定する仕事をしています  
WebBrowser上ではCookieの設定だけしています。  
ここで新たに前回閉じられたタブを次回起動時に復帰させる機能を追加する場合、オブジェクト指向、MVVMを意識した場合どのクラスに書けばいいのでしょうか？  
また設計の指摘ありましたら、お願いします。
CC BY-SA 3.0
2017-10-02T12:52:43.257
38370
2017-10-02T13:40:25.970
20468
question
c#
C#でクラス設計、オブジェクト指向について
感覚的ですが、私がやるなら…  
ユーザ設定や環境を扱うクラスを作ります。そのクラスを起動処理をする箇所から参照してTabConに通知する、みたいな構成にします。
CC BY-SA 3.0
2017-10-02T13:12:24.583
38371
2017-10-02T13:12:24.583
12233
38370
answer
MVVMでということですので、まずタブを表すクラスを定義します。

```

    public sealed class TabViewModel
    {
        // 現在のURLなど
    }
    
```

それからタブ一覧を管理するクラスを作成します。このクラスは`TabControl`や`Form`につき1個のインスタンスを生成してフィールドや`BindingContext`に代入しておくような使い方をします。

```

    public sealed class MainViewModel
    {
        private ObservableCollection<TabViewModel> _Tabs;
    
        public ObservableCollection<TabViewModel> Tabs
        {
            get
            {
                if (_Tabs == null)
                {
                    _Tabs = new ObservableCollection<TabViewModel>();
    
                    // TODO: 前回起動時のタブを追加する (非同期可)
                }
    
                return _Tabs;
            }
        }
    }
    
```

上記のような実装を行うと、`Tabs`の初回アクセス時に保存されているタブの読み込みを開始することができます。またここで使用している`ObservableCollection<T>`には変更通知イベントが用意されており、コントロールは`CollectionChanged`イベントを監視してビューモデル上でのタブの変更を検知することになります。

```

    // コンストラクターやBindingContextChangedイベントなどで実行する
    // MainViewModel vm;
    vm.Tabs.CollectionChanged += Tabs_CollectionChanged;
    
```

`CollectionChanged`イベントではコレクションの変更位置が通知されますので、同じように`TabPage`を変化させます。下のコードではリセットのみを実装していますが、実際には他の4パターンにすべて対応してください。

```

    private static void Tabs_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                // TODO: Add時の処理
                break;
    
            case NotifyCollectionChangedAction.Remove:
                // TODO: Remove時の処理
                break;
    
            case NotifyCollectionChangedAction.Move:
                // TODO: Move時の処理
                break;
    
            case NotifyCollectionChangedAction.Replace:
                // TODO: Replace時の処理
                break;
        }
    
        ResetTabs();
    }
    
    private static void ResetTabs()
    {
        // TabControl tabControl;
        // MainViewModel vm;
    
        tabControl.TabPages.Clear();
        foreach (var t in vm.Tabs)
        {
            var tp = new TabPage();
    
            // TODO: TabPageの初期化
    
            tabControl.TabPages.Add(tp);
        }
    }
    
```

あとは`TabViewModel`/`MainViewModel`にプロパティを増やしつつ、ビュー側で変更に追従する処理を入れたり、ビュー側のイベントハンドラーでビューモデルを操作したりすればよいです。
CC BY-SA 3.0
2017-10-02T13:40:25.970
38374
2017-10-02T13:40:25.970
5750
38370
answer