1

ばかげた(または些細な)ちょっとした質問かもしれませんが、答えがわからないようです。これがケースです-

  1. コンボボックスのUserListとしてを割り当てました。ItemsSourceつまり、私が基本的に行ったことは、参照型を別の型に割り当てることです。
  2. をクリアしましたUserList。だから今私CountItemsSource0のも取得します。
  3. コンボボックスにアイテムが残っています。SelectedItemまた、コンボボックスのをUserオブジェクトにキャストすることもできます。

これが完全なコードです-

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public partial class MainWindow : Window
{
    private List<User> _userList;

    public MainWindow()
    {
        InitializeComponent();
        _userList = new List<User>()
                                  {
                                      new User() {Id = 1, Name = "X"},
                                      new User() {Id = 2, Name = "Y"},
                                      new User() {Id = 3, Name = "Z"}
                                  };
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        this.comboBox1.ItemsSource = _userList;
        this.comboBox1.DisplayMemberPath = "Name";
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        _userList.Clear();

        /* ItemsSource is cleared as well*/
        IEnumerable userList = this.comboBox1.ItemsSource;

        /*I can still get my User*/
        User user = this.comboBox1.SelectedItem as User;
    }
}  

それで、アイテムはどこから来ているのですか?私がそのようなバインディングを行うとき、実際に内部で何が起こりますか?コントロールにはある種のキャッシュがありますか?そのような基本的な考えがないことに気付くのは大変な苦痛です。誰かが舞台裏の詳細を説明できますか?

編集:私はWPFでコードを書きましたが、WinFormsについても同じ質問がありComboboxます。

編集:コンボボックスは、メモリ内のアイテムを表示しませんDatasourceか?そのデータソースに0個のアイテムが含まれている場合、どのようにアイテムを表示しますか?

4

4 に答える 4

2

ItemsSourceいずれかを設定するItemsControlと、リストへの参照がそのItemsプロパティにコピーされます。次に、OnCollectionChangedイベントをサブスクライブし、オブジェクトを作成しCollectionViewます。したがって、画面にはそのcollectionViewが表示されます。

私がソースコードで見つけたように、ItemCollection2つのリストがあります:

internal void SetItemsSource(IEnumerable value)
    {
      //checks are missed
      this._itemsSource = value;
      this.SetCollectionView(CollectionViewSource.GetDefaultCollectionView((object) this._itemsSource, this.ModelParent));
    }

どうやって SelectedItem を取得できますか?

これは、ソースコードをざっと見てからの私の仮定です。

ItemsControl「ビュー」のコレクションがあり、画面にデータを描画する必要があるため、各Viewアイテム(インスタンス)への参照を保存する必要があります。Userそのため、SelectedItem を呼び出すと、保存された参照が返されます。

参照に関する更新

インスタンスがあるとしUserます。メモリにはアドレス 123があります。リストがあります。参照を格納します。その一つが123です。

を設定するItemsSource ItemsControlと、リストへの参照が保存され、Views コレクションが作成されます。各ビューには、アイテムへの参照が格納されます。1つのビューにはアドレス123が格納される。

次に、ユーザーのリストをクリアしました。現在、リストには への参照が含まれていませんUsers。しかし、メモリにはアドレス 123 があり、Userこのアドレスによってのインスタンスがあります。ビューには参照があるため、ガベージ コレクターはそれを破棄しません。

取得すると、アドレス123SelectedItemから User インスタンスが返されます。

var user = new User();

var list = new List<User>();
list.Add(user);

list.Clear();
Console.WriteLine(list.Count()); //prints 0 - list is empty

Console.WriteLine(user == null); //prints false. - user instance is sill exists;
于 2012-09-04T11:46:28.197 に答える
1

@GazTheDestroyer へのコメントへの回答 (「...なぜクリアされないのか、どのようにアイテムを保持するのか?」)

WPF では、 のItemsSourceプロパティを設定するItemsControlと、コントロールはアイテムのリストを でラップしますCollectionView。これは、UI フレームワークで使用するために最適化されたコレクション タイプです。これCollectionViewはコントロールのプロパティに割り当てられItems、表示描画コードが実際に機能するものです。ご覧のとおり、このコレクションは最初に に割り当てたオブジェクトとは完全に分離されてItemsSourceいるため、一方から他方への変更の伝播はありません。これが、元のリストをクリアしても項目がまだコントロール内にある理由です。コントロールは元のリストを無視し、オブジェクトを含む独自のリストを持っています。

ItemsSource値がイベントを発生させる必要があるのはこのためです。具体的INotifyCollectionChanged.NotifyCollectionChangedには、コントロールがItemsリストを更新する必要があることを認識できるようにするためです。 ObservableCollectionこのインターフェイスを実装して正しいイベントを発生させるため、機能は期待どおりに機能します。

これは、WinForms で起こることとはまったく異なることに注意することが非常に重要です。

編集:明確にするために、「ディープコピー」はありません。発生しているコードは、原則として次のようなものです。

private List<object> myCopy;

public void SetItemsSource(List<object> yourCopy)
{
     myCopy = new List<object>();
     foreach (var o in yourCopy)
     {
         myCopy.Add(o);
     }
}

このコードが実行されると、リスト内のすべてのアイテムのコピーが 1 つだけになります。ただし、各項目は両方のリストにあります。を変更、クリア、またはその他の方法で操作した場合yourCopy、 はそれmyCopyについて何も知りません。私のクリアリングリスト内にあるオブジェクトを「破棄」することはできませんyourCopy-あなたがすることは、それらへの独自の参照を解放することだけです.

于 2012-09-04T12:53:08.643 に答える
0

WPFを使用していると仮定します。

List<User>UIがそれ自体を更新するために認識するイベントを発生させません。代わりに使用ObservableCollection<User>すると、コードが機能します。

主な違いは、をObservableCollection実装INotifyCollectionChangedすることです。これにより、UIはコレクションのコンテンツが変更されたことを認識し、のコンテンツを更新できComboBoxます。

(これはWinFormsでは機能しないDataSourceことに注意してください。WinFormsではコントロールのプロパティを設定できますが、同じObservableCollectionトリックはここでは機能しません。)

于 2012-09-04T12:36:19.140 に答える
0

へのコレクション参照を設定するとItemsControl、すべてのコンボが取得するのは参照であり、列挙可能であることがわかっています。

参照を列挙し、アイテムを表示します。深いコピーを行うか浅いコピーを行うかは関係ありません。それが持つのは参照 (実質的にメモリアドレス) だけです。

なんらかの方法でコレクションを変更した場合、何らかの方法で伝えない限り、コンボは知る方法がありません。参照 (アドレス) は変更されていません。すべてがコンボに同じように見えます。オブジェクトが何らかの形で「生きている」と考えているようで、コンボは記憶の変化などを見ることができますか? そうではありません。それが持っているのは、列挙できる参照だけです。内容は変化する可能性がありますが、何らかのトリガーがなければコンボはそれを認識しないため、何もせずに座っています。

ObservableCollectionこれを克服するように設計されています。変更時にイベントを発生させる実装INotifyCollectionChangedを実装しているため、Combo は表示を更新する必要があることを認識しています。

于 2012-09-04T13:35:25.470 に答える