gpt4 book ai didi

c# - WPF - 恢复 ComboBox ItemSsource 中的上一个 SelectedItem 已更改

转载 作者:行者123 更新时间:2023-12-03 10:15:07 25 4
gpt4 key购买 nike

我正在实现一个可以由用户使用按钮刷新的 ComboBox。我试图做到这一点,以便在刷新后如果先前选择的项目仍然存在于 ComboBox 中,则会自动重新选择。

主窗口.xaml:

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

主窗口.xaml.cs:

public MainWindow()
{
InitializeComponent();
DataContext = m_BrowserInstances = new BrowserInstancesViewModel();
}

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

[编辑为当前版本] BrowserInstancesViewModel.cs:

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)时,代码似乎无法正常工作。

最佳答案

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

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

根据您当前的代码更正代码:

if(selectedItem != null)
m_SelectedItem = m_Items.SingleOrDefault(Recover(selectedItem));
if(m_SelectedItem == null)
m_SelectedItem = m_Items[0];

更新:

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

  1. 如果没有进程,您添加的默认 BrowserInstance 对象的 Process 属性值为 null。这会导致 SingleOrDefault 使用的比较代码中出现 NullReferenceException
    通过将前面的 if 更改为

    来修复它
    if(selectedItem != null && selectedItem.Process != null)
  2. Populate 方法的末尾,您为 Items 引发了 PropertyChanged 事件 - 以更新组合框中的值 -对于 SelectedItem - 将所选项目设置为用户之前选择的项目。
    这里的问题是,当 Items 引发 PropertyChanged 时,WPF 会将 SelectedItem 更新为 null,因为它不会在新项目列表中找到之前选择的项目。这有效地覆盖了您在 Populate 方法中计算的新选定项。
    通过不将新选择的项目分配给 m_SelectedItem 而是分配给 selectedItem 并在 PropertyChanged 之后将该值分配给 SelectedItem 来修复它> 引发了 Items 事件:

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

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

    m_Items = new ObservableCollection<BrowserInstance>(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 == selectedItem.Process.MainModule.BaseAddress));

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

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

    selectedItem = m_Items[0];
    }

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

如果您能正确地实现 BrowserInstance 的相等性,您可以使用 WPF 功能来保留当前选定的项目。
Populate 的代码可以这样简化:

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 的相等实现如下所示:

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

关于c# - WPF - 恢复 ComboBox ItemSsource 中的上一个 SelectedItem 已更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16169906/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com