【问题标题】:Automatically select item added to an ObservableCollection自动选择添加到 ObservableCollection 的项目
【发布时间】:2014-09-04 17:58:41
【问题描述】:

每当将一个项目添加到 ObservableCollection 时,我都会尝试在 ListView 中自动选择一个项目。我正在使用 CollectionChanged 事件来监听添加项目的时间,然后选择它。 CollectionChanged 事件似乎发生在 UI 更新之前,因此 SelectedIndex 会相应调整。我尝试设置 SelectedIndex 和 SelectedItem ,但在这两种情况下,添加后的项目最终都被选中。正确的索引是当集合更改时,UI 更新,然后索引由 ListView 递增。

这种现象可以用以下方式来证明:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" DataContext="{Binding Main, Source= {StaticResource Locator}}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
        <ListView ItemsSource="{Binding Items, Mode=TwoWay}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}" Grid.Row="0">
        </ListView>
        <StackPanel Orientation="Horizontal" Grid.Row="1">
            <Button Content="Add Item" Width="75" Command="{Binding AddItemCommand}"/>
            <Label Content="SelectedIndex:"/>
            <Label Content="{Binding SelectedIndex}"/>
            <Label Content="SelectedItem:"/>
            <Label Content="{Binding SelectedItem}"/>
            <Label Content="&lt;- Numbers should match after item added"/>
        </StackPanel>
    </Grid>
</Window>

和 ViewModel:

public class MainViewModel : ViewModelBase
{
    private ICommand addItemCommand;
    /// <summary>
    /// Initializes a new instance of the MainViewModel class.
    /// </summary>
    public MainViewModel()
    {
        Items = new ObservableCollection<string>();
        Items.CollectionChanged += Items_CollectionChanged;
    }

    private int selectedIndex = -1;
    public const string SelectedIndexPropertyName = "SelectedIndex";
    public int SelectedIndex
    {
        get
        {
            return selectedIndex;
        }
        set
        {
            if (selectedIndex != value)
            {
                selectedIndex = value;
                RaisePropertyChanged(SelectedIndexPropertyName);
            }
        }
    }

    private string selectedItem = null;
    public const string SelectedItemPropertyName = "SelectedItem";
    public string SelectedItem
    {
        get
        {
            return selectedItem;
        }
        set
        {
            if (selectedItem != value)
            {
                selectedItem = value;
                RaisePropertyChanged(SelectedItemPropertyName);
            }
        }
    }

    private ObservableCollection<string> items;
    public const string ItemsPropertyName = "Items";
    public ObservableCollection<string> Items
    {
        get
        {
            return items;
        }
        set
        {
            items = value;
            RaisePropertyChanged(ItemsPropertyName);
        }
    }

    private void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
        {
            //SelectedItem = e.NewItems[0];
            SelectedIndex = e.NewStartingIndex;
        }
    }

    public ICommand AddItemCommand
    {
        get
        {
            if (addItemCommand == null)
                addItemCommand = new RelayCommand(() => Items.Add("Item " + items.Count));

            return addItemCommand;
        }
    }
}

我已将示例解决方案上传到www.itzalive.co.uk/AddItemSelection.zip

有人知道如何使用 CollectionChanged 事件选择新添加的项目吗?在我的实际程序中,该项目没有添加到它正在显示的同一位置,因此无法单独设置所选项目。

【问题讨论】:

  • C# 中的 SelectedItem 属性在哪里?
  • 没有包含它,因为它没有被使用它基本上看起来与 SelectedIndex 属性完全相同
  • SelectedItemSelectedIndex 绑定同一个东西,所以我不建议同时设置。如果您删除 SelectedItem 绑定,它会起作用吗?
  • 我已确保我只更改代码中的两个属性中的一个或另一个,因此它们之间没有干扰。
  • 不,只绑定一个或另一个似乎没有什么区别。

标签: c# wpf listview mvvm observablecollection


【解决方案1】:

最好只使用SelectedItem 属性,而不是SelectedIndex 属性:

<ListView ItemsSource="{Binding Items, Mode=TwoWay}" 
    SelectedItem="{Binding SelectedItem, Mode=TwoWay}" ... />

然后在代码中:

YourClass newItem = new YourClass();
Items.Add(newItem);
SelectedItem = newItem;

同时从Items_CollectionChanged 事件处理程序中删除您的代码。如果 UI 尚未更新,您可能还需要调用 NotifyPropertyChanged("Items"); 来更新 UI。


更新>>>

然后尝试将其添加到您的 CollectionChanged 处理程序中:

if (e.Action == NotifyCollectionChangedAction.Add) 
    SelectedItem = e.NewItems[0] as string;

【讨论】:

  • 我正在努力做到这一点,以便可以将项目添加到任何地方的列表中并且它将被选中。这意味着我无法选择下一行中的项目来添加它。
  • 我之前也尝试过,但是我得到了相同的结果。似乎 CollectionChanged 事件在数据和 UI 不同步时发生,因此发生了一些奇怪的更新。
  • 我无法告诉您您没有向我展示的代码有什么问题。请阅读帮助中心的How to create a Minimal, Complete, and Verifiable example 页面,了解如何创建适当的代码示例,然后编辑您的问题。
  • 我很确定错误与已列出的内容有关。我已经用一套完整的代码编辑了这个问题,可以用来轻松地复制这个现象。
  • 好吧,谢谢你浪费我的时间。你能告诉我答案的第一行是什么吗?你接受我的建议了吗?不,你没有,就是为什么我的其余答案对你不起作用。删除SelectedIndex 属性,我的回答会奏效。当我试图提供帮助但用户不听时,这非常令人沮丧。
猜你喜欢
  • 2015-07-13
  • 1970-01-01
  • 2017-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
相关资源
最近更新 更多