首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >WPF -当SelectedItem ComboBox ItemSource更改时恢复以前的ItemSource

WPF -当SelectedItem ComboBox ItemSource更改时恢复以前的ItemSource
EN

Stack Overflow用户
提问于 2013-04-23 12:54:51
回答 1查看 3.1K关注 0票数 3

我正在实现一个可以由用户使用按钮刷新的ComboBox。我正在努力使以前选择的项在刷新后仍然存在于ComboBox中时自动重新选择。

MainWindow.xaml:

代码语言:javascript
复制
<ComboBox Canvas.Left="10" Canvas.Top="10" DisplayMemberPath="Name" IsEnabled="{Binding Path=Enabled}" ItemsSource="{Binding Path=Items}" SelectedItem="{Binding Mode=TwoWay, Path=SelectedItem}" Width="379"/>
<Button Content="{x:Static p:Resources.TextRefresh}" Canvas.Right="10" Canvas.Top="10" Click="OnClickButtonRefresh" Width="75"/>

MainWindow.xaml.cs:

代码语言:javascript
复制
public MainWindow()
{
    InitializeComponent();
    DataContext = m_BrowserInstances = new BrowserInstancesViewModel();
}

private void OnClickButtonRefresh(Object sender, RoutedEventArgs e)
{
    m_BrowserInstances.Populate();
}

编辑为当前版本的 BrowserInstancesViewModel.cs:

代码语言:javascript
复制
public sealed class BrowserInstancesViewModel : ViewModel
{
    private Boolean m_Enabled;
    public Boolean Enabled
    {
        get { return m_Enabled; }
    }

    private BrowserInstance m_SelectedItem;
    public BrowserInstance SelectedItem
    {
        get { return m_SelectedItem; }
        set
        {
            if (m_SelectedItem != value)
            {
                m_SelectedItem = value;
                NotifyPropertyChanged("SelectedItem");
            }
        }
    }

    private ObservableCollection<BrowserInstance> m_Items;
    public ObservableCollection<BrowserInstance> Items
    {
        get { return m_Items; }
    }

    public BrowserInstancesViewModel()
    {
        Populate();
    }

    private static Func<BrowserInstance, Boolean> Recover(BrowserInstance selectedItem)
    {
        return x =>
        {
            Process currentProcess = x.Process;
            Process selectedProcess = selectedItem.Process;

            if (currentProcess.Id != selectedProcess.Id)
                return false;

            if (currentProcess.MainModule.BaseAddress != selectedProcess.MainModule.BaseAddress)
                return false;

            if (currentProcess.MainWindowTitle != selectedProcess.MainWindowTitle)
                return false;

            return true;
        };
    }

    public void Populate()
    {
        BrowserInstance item = m_SelectedItem;
        List<BrowserInstance> items = new List<BrowserInstance>();

        foreach (Process process in Process.GetProcessesByName("chrome"))
            items.Add(new BrowserInstance(process));

        if (items.Count > 0)
        {
            m_Enabled = true;

            m_Items = new ObservableCollection<BrowserInstance>(items.OrderBy(x => x.Process.Id));

            if (item != null)
                m_SelectedItem = m_Items.SingleOrDefault(Recover(item));

            if (m_SelectedItem == null)
                m_SelectedItem = m_Items[0];
        }
        else
        {
            m_Enabled = false;

            m_Items = new ObservableCollection<BrowserInstance>();
            m_Items.Add(new BrowserInstance());

            m_SelectedItem = m_Items[0];
        }

        NotifyPropertyChanged("Enabled");
        NotifyPropertyChanged("Items");
        NotifyPropertyChanged("SelectedItem");
    }
}

我可以拿回以前选择的项目,但有时。当我需要选择一个默认值(索引0)时,如果无法恢复之前选择的项,代码看起来就不能正常工作了。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-04-23 12:58:29

您需要将m_SelectedItem设置为SingleOrDefault(Recover(...))找到的项。

目前,您正在将其设置为旧实例。该实例不再存在于列表中,而且显然您的BrowserInstance类没有实现任何相等的成员。

基于当前代码的正确代码:

代码语言:javascript
复制
if(selectedItem != null)
    m_SelectedItem = m_Items.SingleOrDefault(Recover(selectedItem));
if(m_SelectedItem == null)
    m_SelectedItem = m_Items[0];

更新:

你上传的代码有两个问题。

  1. 如果没有进程,添加的默认BrowserInstance对象的BrowserInstance属性的值是null。这将导致NullReferenceExceptionSingleOrDefault使用的比较代码中出现。 通过将前面的if更改为 if(selectedItem != null && selectedItem.Process != null)
  2. Populate方法的末尾,您将引发用于ItemsPropertyChanged事件--更新组合框中的值-以及为SelectedItem --将选定的项设置为用户先前选择的项。 这里的问题是,当为SelectedItem提出PropertyChanged时,WPF将使用null更新Items,因为它在新项列表中找不到以前选择的项。这有效地覆盖了在Populate方法中计算的新选定项。 通过不将新选定的项分配给m_SelectedItem,而将其赋值给selectedItem,并在引发ItemsPropertyChanged事件之后将该值分配给SelectedItem来修正该问题: 公开无效填充(){ BrowserInstance selectedItem = m_SelectedItem;List items =新List();foreach (Process process in Process.GetProcessesByName(“chrome”) items.Add(new BrowserInstance(process));if (items.Count > 0) { m_Enabled = true;m_Items = new ObservableCollection(items.OrderBy(x => x.Process.Id));if (selectedItem != null && selectedItem.Process != null) selectedItem = m_Items.SingleOrDefault(x => (x.Process.Id == selectedItem.Process.Id) &x.Process.MainModule.BaseAddress == == if (selectedItem == null) selectedItem = m_Items;M_Items.Add(新BrowserInstance());selectedItem = m_Items;}NotifyPropertyChanged(“已启用”);NotifyPropertyChanged(“项”);SelectedItem = selectedItem;}

如果要正确地为BrowserInstance实现相等,则可以使用保留当前选定项的WPF功能。

Populate的代码可以简化如下:

代码语言:javascript
复制
public void Populate()
{
    BrowserInstance selectedItem = m_SelectedItem;
    List<BrowserInstance> items = new List<BrowserInstance>();

    foreach (Process process in Process.GetProcessesByName("chrome"))
        items.Add(new BrowserInstance(process));

    m_Enabled = items.Any();
    m_Items = new ObservableCollection<BrowserInstance>(items.OrderBy(x => x.Process.Id));
    if(!m_Enabled)
        m_Items.Add(new BrowserInstance());

    NotifyPropertyChanged("Enabled");
    NotifyPropertyChanged("Items");
    if (SelectedItem == null)
        SelectedItem = m_Items[0];
}

BrowserInstance的平等实现如下所示:

代码语言:javascript
复制
public sealed class BrowserInstance : IEquatable<BrowserInstance>
{

    // ...

    public bool Equals(BrowserInstance other)
    {
        if (ReferenceEquals(null, other))
            return false;
        if (ReferenceEquals(this, other))
            return true;
        if (m_Process == null)
        {
            if (other.m_Process == null)
                return true;
            return false;
        }

        if (other.m_Process == null)
            return false;

        return m_Process.Id == other.m_Process.Id && m_Process.MainModule.BaseAddress == other.m_Process.MainModule.BaseAddress;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as BrowserInstance);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return m_Process != null ? ((m_Process.Id.GetHashCode() * 397) ^ m_Process.MainModule.BaseAddress.GetHashCode()) : 0;
        }
    }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16169906

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档