WPF 数据绑定 ObservableCollection<T> 到 DataGrid
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15122811/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF DataBinding ObservableCollection<T> to DataGrid
提问by Chutes
I'm trying to create DataGrid in a separate UserControl whose DataContext is a List of T.
我正在尝试在一个单独的 UserControl 中创建 DataGrid,其 DataContext 是 T 的列表。
In the code behind, I create a List, populate the list, then send it to the constructor for the UserControl on which I have the DataGrid I am trying to populate.
在后面的代码中,我创建了一个列表,填充了该列表,然后将它发送到 UserControl 的构造函数,在该构造函数上,我拥有要填充的 DataGrid。
The UserControl class is as follows.
UserControl 类如下。
public partial class QuotePreview : UserControl
{
private static SelectionList previewList = new SelectionList();
public SelectionList PreviewList
{
get { return previewList; }
}
public QuotePreview()
{
InitializeComponent();
}
public QuotePreview(SelectionList selectedOptions)
{
InitializeComponent();
previewList = selectedOptions;
QuotePreviewDataGrid.DataContext = previewList;
}
}
And the Xaml looks like:
Xaml 看起来像:
<DataGrid Name="QuotePreviewDataGrid"
AutoGenerateColumns="False"
ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTextColumn Header="Model Number" Binding="{Binding ModelNumber}"/>
<DataGridTextColumn Header="Description" Binding="{Binding Description}"/>
<DataGridTextColumn Header="List Price per Unit" Binding="{Binding Price}"/>
</DataGrid.Columns>
</DataGrid>
I've tried setting the ItemSource as well using
我也尝试使用设置 ItemSource
QuotePreviewDataGrid.ItemsSource = PreviewList;
I've also tried setting both the data context and the itemsource as well as refreshing:
我还尝试设置数据上下文和项目源以及刷新:
QuotePreviewDataGrid.Items.Refresh();
The databinding I have set to listboxes in the rest of my application works perfectly. In the list boxes I have the itemsource set to {Binding} and the ListItems binding set to {Binding Property}. The datacontext for the listboxes set in the code behind.
我在应用程序的其余部分中设置为列表框的数据绑定工作得很好。在列表框中,我将 itemsource 设置为 {Binding},并将 ListItems 绑定设置为 {Binding Property}。在后面的代码中设置的列表框的数据上下文。
My datagrid here is setup in the same manner, yet for some reason nothing is being displayed inside the grid.
我这里的数据网格以相同的方式设置,但由于某种原因,网格内没有显示任何内容。
When I go through the debugger and watch the flow of information, I can see the List of T, SelectionsList being created and passed to the constructor for the user control where the data grid lies. I can see that the DataContext is indeed being set and shows the items in the list, but when I go back to my appication and try to view the data grid, it's blank.
当我通过调试器并观察信息流时,我可以看到正在创建的 T 列表、SelectionsList 并传递给数据网格所在的用户控件的构造函数。我可以看到 DataContext 确实正在设置并显示列表中的项目,但是当我回到我的应用程序并尝试查看数据网格时,它是空白的。
Any help would be greatly appreciated. I've been trying to wrap my mind around this problem for the last day and a half. Thanks!
任何帮助将不胜感激。在过去的一天半里,我一直在努力解决这个问题。谢谢!
UPDATE
更新
The SelectionList is setup like:
SelectionList 设置如下:
public class SelectionList : List<Selection>
{
public List<Selection> availableSelections = new List<Selection>();
public List<Selection> AvailableSelections
{
get { return availableSelections; }
}
}
and a Selection is then defined by:
然后选择由以下定义:
public class Selection : DependencyObject
{
public bool IsChecked { get; set; }
public string ModelNumber { get; set; }
public string Description { get; set; }
public string Price { get; set; }
}
When the application starts, I build a catalog of existing products (Selections). On different tabs, one for each product family, the datacontext for the products list box is initialized with with available products that it grabs from the catalog. Then pending which product a user selects, the available options or child selections associated with that product are populated into the appropriate list boxes, accessories and warranties.
当应用程序启动时,我会建立一个现有产品(选择)的目录。在不同的选项卡上,每个产品系列一个,产品列表框的数据上下文用它从目录中获取的可用产品进行初始化。然后等待用户选择哪个产品,与该产品相关联的可用选项或子选项被填充到适当的列表框、附件和保证中。
Once a user selects the options they want, a button is clicked to preview the selected items which is supposed to populate the data grid explained above.
一旦用户选择了他们想要的选项,点击一个按钮来预览应该填充上面解释的数据网格的所选项目。
I can build the list of selected options, however when I try to set the data context of the data grid, nothing appears. The Lists for available selections are built and set to the appropriate data context the same way I am trying to do it for the data grid, however the data grid doesn't want to display my information.
我可以构建所选选项的列表,但是当我尝试设置数据网格的数据上下文时,什么也没有出现。可用选择的列表构建并设置为适当的数据上下文,就像我尝试为数据网格做的那样,但是数据网格不想显示我的信息。
UPDATE
更新
So after some more debugging, I've narrowed the problem down a bit. The data binding works as it should. I have no real problems there, I don't think. However, the issue I'm running into now is what I believe to be 2 different instances of my User Control, but only the original is being displayed, not the updated copy.
所以经过一些更多的调试后,我把问题缩小了一点。数据绑定正常工作。我在那里没有真正的问题,我不认为。但是,我现在遇到的问题是我认为我的用户控件有 2 个不同的实例,但只显示原始版本,而不是更新后的副本。
Here's a copy of the class from about with a couple lines I added to help debug the problem.
这是 about 类的副本,我添加了几行来帮助调试问题。
public partial class QuotePreview : UserControl
{
private SelectionList _selectionList;
private SelectionList temp;
public QuotePreview()
{
InitializeComponent();
_selectionList = (SelectionList)this.DataContext;
}
private void QuotePreview_Loaded(object sender, RoutedEventArgs e)
{
_selectionList.SelectedOptions.Add(
new Selection
{
ModelNumber = "this",
Description = "really",
Price = "sucks"
});
}
public QuotePreview(SelectionList selectedOptions)
{
InitializeComponent();
_selectionList = (SelectionList)this.DataContext;
temp = selectedOptions;
_selectionList.AddRange(selectedOptions);
QuotePreview_Loaded();
}
private void QuotePreview_Loaded()
{
foreach (var options in temp.SelectedOptions)
{
_selectionList.SelectedOptions.Add(options);
}
QuotePreviewDataGrid.ItemsSource = _selectionList.SelectedOptions;
}
}
The implementation of the default constructor, is called every time the user control / tab, is clicked on. When that happens, _selectionList is set to the data context of the user control, followed by the Loaded Event which adds a line to my data grid.
每次单击用户控件/选项卡时都会调用默认构造函数的实现。发生这种情况时,_selectionList 被设置为用户控件的数据上下文,然后是加载事件,它向我的数据网格添加一行。
In another user control where I select the options I want to add to my data grid user control, I click a button that creates a list of the options I want to be added and calls the custom constructor I wrote. Once the constructor finishes, it calls a custom Loaded Event method that I created for shits and giggles, that adds the selected options to my _selectionList.
在另一个用户控件中,我选择要添加到数据网格用户控件的选项,单击一个按钮,创建要添加的选项列表并调用我编写的自定义构造函数。构造函数完成后,它会调用我为狗屎和傻笑创建的自定义加载事件方法,该方法将选定的选项添加到我的 _selectionList。
Now once I click on the data grid user control again, it goes through the whole default process, and adds another default line.
现在,一旦我再次单击数据网格用户控件,它就会经历整个默认过程,并添加另一个默认行。
If I go back a tab and say I want these options again and go back to the data grid, it again goes through the default process and adds another default line.
如果我返回一个选项卡并说我再次想要这些选项并返回到数据网格,它会再次通过默认过程并添加另一个默认行。
Whats most intriguing though is that I can see both of the selectionLists build since I dont clear the in between processes. I see a list build of the options i want to display and a list build of the default options build...
最有趣的是我可以看到两个 selectionLists 构建,因为我没有清除进程之间的。我看到了我想要显示的选项的列表构建和默认选项构建的列表构建...
Oh, also, SelectionList does implement ObservableCollection.
哦,还有,SelectionList 确实实现了 ObservableCollection。
采纳答案by Chutes
I finally came up with a solution to the problem.
我终于想出了解决问题的办法。
public static class QuotePreview
{
public static ObservableCollection<PurchasableItem> LineItems { get; private set; }
static QuotePreview()
{
LineItems = new ObservableCollection<PurchasableItem>();
}
public static void Add(List<PurchasableItems> selections)
{
foreach (var selection in selections)
{
LineItems.Add(selection);
}
}
public static void Clear()
{
LineItems.Clear();
}
}
public class QuoteTab : TabItem
{
public ObservableCollection<PurchasableItem> PreviewItems { get; private set; }
public QuoteTab()
{
Initialize()
PreviewItems = QuotePreview.LineItems;
DataGrid.ItemSource = PreviewItems
}
}
回答by Alastair Pitts
Try changing:
尝试改变:
QuotePreviewDataGrid.DataContext = previewList;
to
到
this.DataContext = previewList;
My suspicion is that the ItemsSource="{Binding}"in your xaml is overriding the DataContext code in your constructor.
我怀疑ItemsSource="{Binding}"您的 xaml 中的 覆盖了构造函数中的 DataContext 代码。
By changing the previewList to be DataContext of the entire UserControl, then the binding of the DataGrid's ItemsSourcecan correctly evaluate.
通过将 previewList 更改为整个 UserControl 的 DataContext,则ItemsSource可以正确评估DataGrid 的绑定。
On a side note, I would start looking into the use of ObservableCollection<T>and the MVVM design pattern. An issue you might end up with is that your DataGriddoesn't update when the underlying list changes, using the ObservableCollection<T>will fix this.
附带说明一下,我将开始研究ObservableCollection<T>MVVM 设计模式的使用。您最终可能会遇到的一个问题是,DataGrid当基础列表更改时,您不会更新,使用ObservableCollection<T>will 解决此问题。
Using the MVVM design pattern will give you a good separation of your logic and data (in this case your list and how it's loaded) from the physical display (the DataGrid)
使用 MVVM 设计模式将使您的逻辑和数据(在这种情况下是您的列表及其加载方式)与物理显示(DataGrid)很好地分离

