Click here to Skip to main content
15,887,585 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I have a MVVM data-bound ComboBox that looks like this:

XML
<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:

C#
public MainWindow()
{
    InitializeComponent();
    DataContext = m_ViewModel = new ViewModel();
}

private void ClickRefresh(Object sender, RoutedEventArgs e)
{
    m_ViewModel.Populate();
}


Here is my ViewModel.cs:

C#
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:

C#
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
Posted
Updated 26-Apr-13 6:31am
v2
Comments
supernorb 26-Apr-13 13:03pm    
Wow, too much code, I bet you have to wait for a long time before anyone considering your code and give some answer.
[no name] 26-Apr-13 13:06pm    
Agreed. I won't debug your code for you and I certainly will not download a file from and unknown source.
Sergey Alexandrovich Kryukov 26-Apr-13 16:01pm    
Me neither. Care to try, anyone? :-)
—SA

1 solution

Your issue is here:

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;
    }
}


Process.GetProcesses() will always return something, therefore if(processInstances.Count==0) will always be false. In turn the else always fires and therefore as you have set m_SelectedItem = null then the if(m_SelectedItem==null) will be true and so it sets it to the first item.

That is your problem.

----------------

When your program is running and you have cleared the processes you are expecting to be running, open task manager and ensure they are actually all gone.

---------------

Also, think there is an issue with your binding as well, but I'm not sure exactly.
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900