【问题标题】:How to implement selectable list for WPF如何为 WPF 实现可选列表
【发布时间】:2020-01-02 00:53:55
【问题描述】:

这似乎是一个简单的问题让我困惑了一段时间,所以我很感激一些建议。

我需要实现可选列表以在 WPF 中使用。由于列表可能很长,用户通常只会选择几个项目,我认为最好的方法是只获取一次完整列表,然后只列出我的主对象(MyParent)的每个实例的选定对象。 MyParent 也可以多次实例化,用户通常一次使用多个实例。我希望用户能够查看包含可能项目的整个列表并能够选择他们想要的内容。我不确定如何绑定这些属性

我的代码(简化和通用名称):

// item model:
public class MyItem
{
    public int ItemId { get; set; }
    public string ItemName { get; set; }
    public bool IsSelected { get; set; } = false;
}

// items factory (ideally entire list should only be
// pulled once in a program lifetime hence singleton):
public class MyItemsFactory
{
    private ObservableCollection<MyItem> myItems => new ObservableCollection<MyItem>();
    public static ObservableCollection<MyItem> MyItems => Instance.myItems;

    private MyItemsFactory()
    {
        GetItems();
    }
    private void GetItems()
    {
        // generate some sample data
        var i1 = new MyItem() { ItemId = 1, ItemName = "Item 1" };
        var i2 = new MyItem() { ItemId = 2, ItemName = "Item 2" };
        var i3 = new MyItem() { ItemId = 3, ItemName = "Item 3" };
        var i4 = new MyItem() { ItemId = 4, ItemName = "Item 4" };
        myItems.Add(i1);
        myItems.Add(i2);
        myItems.Add(i3);
        myItems.Add(i4);
    }

    #region Singleton Implementation
    private static readonly Lazy<MyItemsFactory> instance = new Lazy<MyItemsFactory>(() => new MyItemsFactory());
    public static MyItemsFactory Instance => instance.Value;
    #endregion
}

// parent class
public class MyParent
{
    public int ParentId { get; set; }
    public ObservableCollection<MyItem> MySelectedItems { get; set; } = new ObservableCollection<MyItem>();
    public MyParent()
    {
        GetSelectedItems();
    }
    private void GetSelectedItems()
    {
        // generate some sample data
        var si2 = new MyItem() { ItemId = 2, ItemName = "Item 2", IsSelected = true };
        var si4 = new MyItem() { ItemId = 4, ItemName = "Item 4", IsSelected = true };
        MySelectedItems.Add(si2);
        MySelectedItems.Add(si4);
        // how to include remaining MyItemsFactory.MyItems here?
    }
}

我的用户控件:

<!-- DataContext is set to one of the instance of MyParent -->
<ListView ItemsSource="{Binding MySelectedItems}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Selected">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <ToggleButton
                            IsChecked="{Binding IsSelected}"
                            Content="Selected"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Header="Item Name">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <ToggleButton Content="Selected"
                                        IsChecked="{Binding IsSelected}"
                                        Command="{x:Static c:CommandManager.SelectItem}"
                                        CommandParameter="{Binding}"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

这很好用,但当然只显示 MySelectedItems。我的意图是根据 MyParent 实例的 MySelectedItems 显示所有项目(例如来自 MyItemsFactory.MyItems 的项目)。非常感谢。

【问题讨论】:

  • 不太清楚你在这里问什么。您为什么要维护当前选定项目的列表?每个项目已经有一个IsSelected 属性,当用户切换按钮时会更新。只需将您的 ItemsControl ItemsSource 绑定到 MyItems 以便您看到所有这些。
  • 将 ItemsSource 绑定到 MyItems,将 SelectedItems 绑定到 MySelectedItems 有什么问题?
  • 通过MyParent 上的属性公开MyItemsFactory.MyItems
  • @MarkFeldman 如果我这样做,MyParent 的每个实例都会有相同的 MyItems 列表
  • @RobinBennett 我还没有检查过。我认为它不起作用,因为 MyItems 和 MySelectedItems 中的项目指向不同的对象(例如 si2 != i2)

标签: c# wpf singleton factory observablecollection


【解决方案1】:

暴露MyParent中所有项目的单例集:

public class MyParent
{
    public MyItems 
    {
        get
        {
            return MyItemsFactory.MyItems;
        }
    }
}

ListView 然后可以绑定到该属性:

<!-- DataContext is set to one of the instance of MyParent -->
<ListView ItemsSource="{Binding MyItems}">
...

【讨论】:

  • 不是每个 MyParent 实例都指向同一个集合(因为它是单例的)和其中的选定项目吗?我必须在 MyParent 的每个实例中都有相同的基本集合,但该集合中的选定项目可能不同。
  • 所有MyParent 都会指向你的单身MyItemsFactoryMyItems,因为你说你想分享这些。每个MyParent 都有自己的“选定项目集合”——MyItems 的可变子集。我的示例不包括您已经拥有的代码 - 即 MySelectedItems - 仍然存在(尽管我也同意马克的观点,即您应该使用项目的 IsSelected 属性,而不是单独的集合来定义“选定项目”)。
  • 如果您仍然不确定如何在 DataContext/ViewModel 中同时区分“所有项目”和“选定项目”,那么请这么说,我可能会在我的答案中添加更多内容澄清。我以为您只是想知道如何将 MyItems 的单例集合放入 ListView,但也许您不确定如何拥有单独的集合。
  • 很抱歉让您感到困惑。我看到MyItems 中的IsSelected 属性具有误导性,我可能想将其从模型中删除。我想我改写的问题是我现在是否正确地制作了MySelectedItems 子集,所以@RobinBennett 的建议会起作用? ListView 似乎没有公开我可以将MySelectedItems 绑定到的 SelectedItems 属性。
  • 我遇到了无法在 DataGrid 中绑定 SelectedItems 的问题 - 也许这也是 ListView 的问题(我不知道)。我求助于 View 代码隐藏中的事件处理来解决 DataGrid 的问题。如果您无法将 ListView.SelectedItems 绑定到 DataContext 中的 SelectedItems,那么您可能也需要解决它。尝试搜索“绑定 ListView SelectedItems”。对不起,我没有更多帮助。 :)
猜你喜欢
  • 2011-05-30
  • 2014-06-10
  • 2020-01-11
  • 2014-12-16
  • 1970-01-01
  • 1970-01-01
  • 2022-07-06
  • 1970-01-01
  • 2014-08-27
相关资源
最近更新 更多