使用ComboBox SelectedItem获得CRAZY [英] Getting CRAZY with ComboBox SelectedItem

查看:111
本文介绍了使用ComboBox SelectedItem获得CRAZY的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个MVVM数据绑定的ComboBox,如下所示:



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"/>





然后,在我的MainWindow.xaml.cs中:





Then, in my MainWindow.xaml.cs:

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

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





这是我的ViewModel.cs:





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





这是我的ProcessInstance类相关代码:





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





现在这里发生的事情......我在没有流程实例的情况下启动应用程序:



http://i.stack.imgur.com/VxF6y.png [ ^ ]



然后我打开一个或多个流程实例,然后单击刷新按钮。第一个被ComboBox选为默认值...我可以选择一个或选择另一个,这没关系:



http://i.stack.imgur.com/tY8ar.png [ ^ ]



现在我关闭每个流程实例我再次单击刷新按钮。在这种情况下发生的是Populate()方法将SelectedItem和Items都设置为null,因此ComboBox看起来是空的,然后它禁用ComboBox并使水印标签可见。但这是我得到的:



http:// i .stack.imgur.com / WRsnr.png [ ^ ]



之前的SelectedItem仍在那里。为什么?为什么?!?!







这是下载项目的链接:http://www.filedropper.com/damncb



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

推荐答案

您的问题在这里:



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()将始终返回一些内容,因此if(processInstances.Count = = 0)永远是假的。反过来,else总是触发,因此你设置m_SelectedItem = null然后if(m_SelectedItem == null)将为true,因此它将它设置为第一项。



这是你的问题。



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



当你的程序运行并清除了你期望运行的进程时,打开任务管理器并确保它们实际上都已消失。



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



另外,想想你的绑定也有问题,但我是不确定。



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.


这篇关于使用ComboBox SelectedItem获得CRAZY的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆