将项目添加到未知类型的 ObservableCollection

发布于 2024-08-17 18:59:56 字数 2943 浏览 4 评论 0原文

我正在使用 MVVM 设计模式创建一个 WPF 应用程序,并且尝试创建一个组合框,允许用户在运行时编辑下拉列表中的项目,类似于 MS Access 2007 让您执行此操作的方式。因此,我创建了一个构建在组合框之上的用户控件...当显示下拉列表时,列表下方有一个按钮,可打开另一个窗口来编辑列表中的项目。非常简单,但是弹出窗口对列表中的项目类型一无所知,除了它们是 ObservableCollection 的某种类型之外。

您可以查看我试图解释的内容的屏幕截图 此处

例如,在视图上,我将自定义组合框绑定到 ObservableCollection。我单击按钮编辑列表,弹出窗口显示文本框中的所有项目供用户编辑。问题是尝试从弹出窗口添加/更新/删除 ObservableCollection 中的项目。除了显示字段的名称 (this.DisplayMemberPath) 之外,该窗口不知道有关 ObservableCollection 的任何信息。

我知道我始终可以将组合框绑定到 ObservableCollectionIEnumerable,但我使用 LINQ to SQL 来填充组合框项目,并且我需要了解所有对象的更改跟踪,以便我可以更新对列表所做更改的数据库。因此,(我认为)我必须使用 ObservableCollection来监视更改跟踪。我还考虑过使用 CollectionChanged 事件来更新数据库的想法,但我想知道是否有更干净的方法。

我有一种感觉,我需要使用 Reflection 来更新列表,但我不太熟悉使用 Reflection。

这是我用于显示弹出窗口的源代码:

public event EventHandler<EventArgs> EditListClick;
private void EditButton_Click(object sender, RoutedEventArgs e)
{
    if (this.EditListDialog == null)
    {
        // Create the default dialog window for editing the list
        EditListDialogWindow dialog = new EditListDialogWindow();
        string items = string.Empty;

        if (this.Items != null)
        {
            // Loop through each item and flatten the list
            foreach (object item in this.Items)
            {
                PropertyInfo pi = item.GetType().GetProperty(this.DisplayMemberPath);
                string value = pi.GetValue(item, null) as string;

                items = string.Concat(items, ((items == string.Empty) ? items : "\n") + value);
            }

            // Now pass the information to the dialog window
            dialog.TextList = items;
        }

        // Set the owner and display the dialog
        dialog.Owner = Window.GetWindow(this);
        dialog.ShowDialog();

        // If the user has pressed the OK button...
        if (dialog.DialogResult.HasValue && dialog.DialogResult.Value)
        {
            // Make sure there has been a change
            if (items != dialog.TextList)
            {
                // Unflatten the string into an Array
                string[] itemArray = dialog.TextList.Split(new string[]{"\n", "\r"}, StringSplitOptions.RemoveEmptyEntries);

                // Add the items to the list
                foreach (string item in itemArray)
                {
                    // This is where I run into problems...
                    // Should I be using reflection here??
                    ((ObservableCollection<object>)this.ItemsSource).Add(item.Trim());
                }
            }
        }
    }

    if (EditListClick != null)
        EditListClick(this, EventArgs.Empty);
}

I'm creating a WPF application using the MVVM design pattern, and I'm trying to create a Combobox that allows the user to edit the items in the drop-down list at runtime, similar to the way MS Access 2007 lets you do it. So I've created a UserControl that builds on top of a Combobox... when the drop-down is shown, there is a button below the list that opens another window to edit the items in the list. Pretty straight forward, but the popup window knows nothing about the type of items in the list, other than they are of some type of an ObservableCollection.

You can view a screenshot of what I'm trying to explain HERE.

For instance, on the View, I bind the custom combobox to ObservableCollection<Sizes>. I click the button to edit the list and the popup window displays all of the items in a TextBox for the user to edit. The problem is trying to add/update/delete items in the ObservableCollection from the popup window. This window does not know anything about the ObservableCollection, other than the name of the display field (this.DisplayMemberPath).

I know that I could always bind the combobox to an ObservableCollection<string>, or IEnumerable<string>, but I am using LINQ to SQL to populate the combobox items, and I need to be aware of change tracking on all of my objects so I can update the database of changes made to the list. Therefore, (I think) I must use ObservableCollection<Sizes> in order to monitor change tracking. I've also toyed with the idea of using the CollectionChanged Event to update the database, but I'm wondering if there is a cleaner method.

I have a feeling that I'll be needing to use Reflection to update the list, but I'm not very well versed in working with Reflection.

Here's my source code for displaying the popup window:

public event EventHandler<EventArgs> EditListClick;
private void EditButton_Click(object sender, RoutedEventArgs e)
{
    if (this.EditListDialog == null)
    {
        // Create the default dialog window for editing the list
        EditListDialogWindow dialog = new EditListDialogWindow();
        string items = string.Empty;

        if (this.Items != null)
        {
            // Loop through each item and flatten the list
            foreach (object item in this.Items)
            {
                PropertyInfo pi = item.GetType().GetProperty(this.DisplayMemberPath);
                string value = pi.GetValue(item, null) as string;

                items = string.Concat(items, ((items == string.Empty) ? items : "\n") + value);
            }

            // Now pass the information to the dialog window
            dialog.TextList = items;
        }

        // Set the owner and display the dialog
        dialog.Owner = Window.GetWindow(this);
        dialog.ShowDialog();

        // If the user has pressed the OK button...
        if (dialog.DialogResult.HasValue && dialog.DialogResult.Value)
        {
            // Make sure there has been a change
            if (items != dialog.TextList)
            {
                // Unflatten the string into an Array
                string[] itemArray = dialog.TextList.Split(new string[]{"\n", "\r"}, StringSplitOptions.RemoveEmptyEntries);

                // Add the items to the list
                foreach (string item in itemArray)
                {
                    // This is where I run into problems...
                    // Should I be using reflection here??
                    ((ObservableCollection<object>)this.ItemsSource).Add(item.Trim());
                }
            }
        }
    }

    if (EditListClick != null)
        EditListClick(this, EventArgs.Empty);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

蒗幽 2024-08-24 18:59:56

听起来您需要了解列表,但不需要了解具体类型。这就是非通用接口的用武之地;尝试以 IList (其中包含所有索引器/添加/删除等)、INotifyCollectionChanged (用于通知)等方式访问列表。

在更一般的情况下,还有 < code>IBindingList / IBindingListView / ITypedList 等,但我认为在这种情况下您不需要这些。

It sounds like you need to know about the list, but not the specific types. That is where the non-generic interfaces come in; try accessing the list as IList (which has all the indexer / Add / Remove etc), INotifyCollectionChanged (for notifications), etc.

In the more general case there is also IBindingList / IBindingListView / ITypedList etc, but I don't think you'll need those in this case.

水水月牙 2024-08-24 18:59:56

您是否尝试过使用 IValueConverter

当您将 ObservbleCollection 绑定到自定义 ComboBox 时,请设置自定义 IValueConverter。他定义了 2 个方法,ConvertConvertBack。这个想法是,你可以转换类型。

在这种情况下,您可以拥有您的 ObservableCollection,绑定转换器将获取它并将其转换为所需的类型。

如果您在集合绑定上设置转换器,则可以在 ObservableCollectionObservableCollection 之间进行转换。

另一个选项是在自定义 ComboBox 内部设置 IValueConverter,并执行从 Sizesstring 的转换。另一个选项是指定一个包含绑定和转换的项目模板。

HtH。

Have you tried using an IValueConverter?

When you bind the ObservbleCollection to the custom ComboBox, set a custom IValueConverter. T His defines 2 methods, Convert and ConvertBack. The idea is, that you can convert types.

In this case, you can have your ObservableCollection<Sizes> and the binding converter will take that and convert it to the required type.

If you set the converter on the collection binding, you can convert to and from ObservableCollection<Sizes> and ObservableCollection<string>.

The other option is set the IValueConverter internally to the custom ComboBox and do the conversion from Sizes to string. Another option, in conjunction is to specific a itemtemplate the contains the binding and conversion.

HtH.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文