将项目添加到未知类型的 ObservableCollection
我正在使用 MVVM 设计模式创建一个 WPF 应用程序,并且尝试创建一个组合框,允许用户在运行时编辑下拉列表中的项目,类似于 MS Access 2007 让您执行此操作的方式。因此,我创建了一个构建在组合框之上的用户控件...当显示下拉列表时,列表下方有一个按钮,可打开另一个窗口来编辑列表中的项目。非常简单,但是弹出窗口对列表中的项目类型一无所知,除了它们是 ObservableCollection 的某种类型之外。
您可以查看我试图解释的内容的屏幕截图 此处。
例如,在视图上,我将自定义组合框绑定到 ObservableCollection
我知道我始终可以将组合框绑定到 ObservableCollection
或 IEnumerable
,但我使用 LINQ to SQL 来填充组合框项目,并且我需要了解所有对象的更改跟踪,以便我可以更新对列表所做更改的数据库。因此,(我认为)我必须使用 ObservableCollection
我有一种感觉,我需要使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
听起来您需要了解列表,但不需要了解具体类型。这就是非通用接口的用武之地;尝试以
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.您是否尝试过使用 IValueConverter?
当您将 ObservbleCollection 绑定到自定义 ComboBox 时,请设置自定义 IValueConverter。他定义了 2 个方法,
Convert
和ConvertBack
。这个想法是,你可以转换类型。在这种情况下,您可以拥有您的
ObservableCollection
,绑定转换器将获取它并将其转换为所需的类型。如果您在集合绑定上设置转换器,则可以在
ObservableCollection
和ObservableCollection
之间进行转换。另一个选项是在自定义 ComboBox 内部设置 IValueConverter,并执行从
Sizes
到string
的转换。另一个选项是指定一个包含绑定和转换的项目模板。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
andConvertBack
. 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>
andObservableCollection<string>
.The other option is set the IValueConverter internally to the custom ComboBox and do the conversion from
Sizes
tostring
. Another option, in conjunction is to specific a itemtemplate the contains the binding and conversion.HtH.