title: ComboBox ItemsSource changed => SelectedItem is ruined
body: <p>Ok, this has been bugging me for a while now. And I wonder how others handle the following case:</p>
  
  <pre><code>&lt;ComboBox ItemsSource="{Binding MyItems}" SelectedItem="{Binding SelectedItem}"/&gt;
  </code></pre>
  
  <p>The DataContext object's code:</p>
  
  <pre><code>public ObservableCollection&lt;MyItem&gt; MyItems { get; set; }
  public MyItem SelectedItem { get; set; }
  
  public void RefreshMyItems()
  {
      MyItems.Clear();
      foreach(var myItem in LoadItems()) MyItems.Add(myItem);
  }
  
  public class MyItem
  {
      public int Id { get; set; }
      public override bool Equals(object obj)
      {
          return this.Id == ((MyItem)obj).Id;
      }
  }
  </code></pre>
  
  <p>Obviously when the <code>RefreshMyItems()</code> method is called the combo box receives the Collection Changed events, updates its items and does not find the SelectedItem in the refreshed collection => sets the SelectedItem to <code>null</code>. But I would need the combo box to use <code>Equals</code> method to select the correct item in the new collection.</p>
  
  <p>In other words - the ItemsSource collection still contains the correct <code>MyItem</code>, but it is a <code>new</code> object. And I want the combo box to use something like <code>Equals</code> to select it automatically (this is made even harder because first the source collection calls <code>Clear()</code> which resets the collection and already at that point the SelectedItem is set to <code>null</code>).</p>
  
  <p><strong>UPDATE 2</strong> Before copy-pasting the code below please note that it is far from perfection! And note that it does not bind two ways by default.</p>
  
  <p><strong>UPDATE</strong> Just in case someone has the same problem (an attached property as proposed by Pavlo Glazkov in his answer):</p>
  
  <pre><code>public static class CBSelectedItem
  {
      public static object GetSelectedItem(DependencyObject obj)
      {
          return (object)obj.GetValue(SelectedItemProperty);
      }
  
      public static void SetSelectedItem(DependencyObject obj, object value)
      {
          obj.SetValue(SelectedItemProperty, value);
      }
  
      // Using a DependencyProperty as the backing store for SelectedIte.  This enables animation, styling, binding, etc...
      public static readonly DependencyProperty SelectedItemProperty =
          DependencyProperty.RegisterAttached("SelectedItem", typeof(object), typeof(CBSelectedItem), new UIPropertyMetadata(null, SelectedItemChanged));
  
  
      private static List&lt;WeakReference&gt; ComboBoxes = new List&lt;WeakReference&gt;();
      private static void SelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
          ComboBox cb = (ComboBox) d;
  
          // Set the selected item of the ComboBox since the value changed
          if (cb.SelectedItem != e.NewValue) cb.SelectedItem = e.NewValue;
  
          // If we already handled this ComboBox - return
          if(ComboBoxes.SingleOrDefault(o =&gt; o.Target == cb) != null) return;
  
          // Check if the ItemsSource supports notifications
          if(cb.ItemsSource is INotifyCollectionChanged)
          {
              // Add ComboBox to the list of handled combo boxes so we do not handle it again in the future
              ComboBoxes.Add(new WeakReference(cb));
  
              // When the ItemsSource collection changes we set the SelectedItem to correct value (using Equals)
              ((INotifyCollectionChanged) cb.ItemsSource).CollectionChanged +=
                  delegate(object sender, NotifyCollectionChangedEventArgs e2)
                      {
                          var collection = (IEnumerable&lt;object&gt;) sender;
                          cb.SelectedItem = collection.SingleOrDefault(o =&gt; o.Equals(GetSelectedItem(cb)));
                      };
  
              // If the user has selected some new value in the combo box - update the attached property too
              cb.SelectionChanged += delegate(object sender, SelectionChangedEventArgs e3)
                                         {
                                             // We only want to handle cases that actually change the selection
                                             if(e3.AddedItems.Count == 1)
                                             {
                                                 SetSelectedItem((DependencyObject)sender, e3.AddedItems[0]);
                                             }
                                         };
          }
  
      }
  }
  </code></pre>