I have a MVVM data-bound ComboBox that looks like this:
<ComboBox Canvas.Left="5" Canvas.Top="5" IsEnabled="{Binding Path=ComboBoxEnabled}" ItemsSource="{Binding Path=Items}" SelectedItem="{Binding Mode=TwoWay, Path=SelectedItem}" Width="250">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}" Text="{Binding}" TextTrimming="CharacterEllipsis"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label Canvas.Left="5" Canvas.Top="4" TextOptions.TextFormattingMode="Display" Content="No process instances have been found." Height="{DynamicResource {x:Static SystemParameters.WindowCaptionHeightKey}}" IsEnabled="False" Visibility="{Binding Path=WatermarkVisibility}" Width="250"/>
<Button Canvas.Right="5" Canvas.Top="5" Click="ClickRefresh" Content="Refresh" Width="75"/>
Then, in my MainWindow.xaml.cs:
public MainWindow()
{
InitializeComponent();
DataContext = m_ViewModel = new ViewModel();
}
private void ClickRefresh(Object sender, RoutedEventArgs e)
{
m_ViewModel.Populate();
}
Here is my ViewModel.cs:
public ProcessInstance SelectedItem
{
get { return m_SelectedItem; }
set
{
if (m_SelectedItem != value)
{
m_SelectedItem = value;
NotifyPropertyChanged("SelectedItem");
}
}
}
public ObservableCollection<ProcessInstance> Items
{
get { return m_Items; }
private set
{
if (m_Items != value)
{
m_Items = value;
NotifyPropertyChanged("Items");
}
}
}
public ViewModel()
{
Populate();
}
public void Populate()
{
ProcessInstance selectedItem = m_SelectedItem;
SelectedItem = null;
Items = null;
List<ProcessInstance> processInstances = new List<ProcessInstance>();
foreach (Process process in Process.GetProcesses())
{
if (...)
processInstances.Add(new ProcessInstance(process));
}
if (processInstances.Count == 0)
{
ComboBoxEnabled = false;
WatermarkVisibility = Visibility.Visible;
}
else
{
Items = new ObservableCollection<ProcessInstance>(processInstances.OrderBy(x => x.Process.Id));
if (selectedItem != null)
SelectedItem = m_Items.SingleOrDefault(x => x.ProcessEquals(selectedItem));
if (m_SelectedItem == null)
SelectedItem = m_Items[0];
ComboBoxEnabled = true;
WatermarkVisibility = Visibility.Hidden;
}
}
And here is my ProcessInstance class relevant code:
public override Boolean Equals(Object obj)
{
return Equals(obj as ProcessInstance);
}
public override Int32 GetHashCode()
{
Int32 hashCode;
if ((m_Process == null) || m_Process.HasExited)
hashCode = 0;
else
{
hashCode = (m_Process.Id.GetHashCode() * 397) ^ m_Process.MainModule.BaseAddress.GetHashCode();
if (!String.IsNullOrEmpty(m_Process.MainWindowTitle))
hashCode = (hashCode * 397) ^ m_Process.MainWindowTitle.GetHashCode();
}
return hashCode;
}
public override String ToString()
{
String processId = process.Id.ToString("X8", CultureInfo.CurrentCulture);
String windowTitle = (process.MainWindowTitle.Length > 0) ? process.MainWindowTitle : "NULL";
return String.Format(CultureInfo.CurrentCulture, "[{0}] {1} - {2}", type, processId, windowTitle);
}
public Boolean Equals(ProcessInstance other)
{
if (other == null)
return false;
if (ReferenceEquals(this, other))
return true;
if (m_Process == null)
{
if (other.Process == null)
return true;
return false;
}
if (other.Process == null)
return false;
return ((m_Process.Id == other.Process.Id) && (m_Process.MainModule.BaseAddress == other.Process.MainModule.BaseAddress) && (m_Process.MainWindowTitle == other.Process.MainWindowTitle));
}
public Boolean ProcessEquals(ProcessInstance other)
{
if (other == null)
throw new ArgumentNullException("other");
if (m_Process == null)
return (other.Process == null);
if (other.Process == null)
return false;
return ((m_Process.Id == other.Process.Id) && (m_Process.MainModule.BaseAddress == other.Process.MainModule.BaseAddress));
}
Now here is what happens... I start the application while no process instances exist:
http://i.stack.imgur.com/VxF6y.png[
^]
Then I open one or more process instances and I click the Refresh button. The first one is selected by ComboBox as default... I can keep that one selected or select another one, it doesn't matter:
http://i.stack.imgur.com/tY8ar.png[
^]
Now i close every process instance and I click Refresh button again. What happens in this case is that the Populate() method sets both SelectedItem and Items to null, so the ComboBox looks empty, and then it disables the ComboBox and makes the watermark Label visible. But here is what I get:
http://i.stack.imgur.com/WRsnr.png[
^]
The previous SelectedItem is still there. Why? WHY?!?!
Here is a link to download the project:
http://www.filedropper.com/damncb