LINQ, group by, and WPF Data Binding - CodePr...
来源:百度文库 编辑:神马文学网 时间:2024/07/03 08:03:57
LINQ, group by, and WPF Data Binding
By r.stropekWPF data binding works great with LINQ! This article shows how to create a hierarchical result set by using LINQ's group by clause and how to consume it in WPF data binding. C# (C#1.0, C#2.0, C#3.0), Windows (WinXP, Vista), .NET (.NET3.0, .NET3.5), WPF, LINQ, Silverlight, Dev Revision: 2 (See All) Posted: 14 Oct 2008 Views: 15,713 Bookmarked: 19 times Announcements Write an iPhone Tutorial, Win an iPad Local Government Windows Azure Competition VS2010 Tech Summit Free, on-demand Monthly Competition The Daily Insider Google ditches Windows on security concerns Daily IT news: Signup now. ArticlesDesktop DevelopmentButton ControlsClipboardCombo & List BoxesDialogs and WindowsDesktop GadgetsDocument / ViewEdit ControlsFiles and FoldersGrid & Data ControlsList ControlsMenusMiscellaneousPrintingProgress ControlsSelection ControlsShell and IE programmingSmart ClientSplitter WindowsStatic & Panel ControlsStatus BarTabs & Property PagesToolbars & Docking windowsTree ControlsWeb DevelopmentAjaxApplications & ToolsASPASP.NETASP.NET ControlsATL ServerCachingCharts, Graphs and ImagesClient side scriptingCustom ControlsHTML / CSSISAPISite & Server ManagementSession StateSilverlightTrace and LogsUser ControlsValidationView StateWAP / WMLWeb SecurityWeb ServicesPHPMobile DevelopmentiPhoneAndroidWindows MobilePalmMiscellaneousBlackBerryEnterprise SystemsContent Management ServerMicrosoft BizTalk ServerMicrosoft ExchangeOffice DevelopmentSharePoint ServerDatabaseDatabaseSQL Reporting ServicesMultimediaAudio and VideoDirectXGDIGDI+General GraphicsOpenGLLanguagesC / C++ LanguageC++ / CLIC#MSILVBScriptVB.NETVB6 InteropOther .NET LanguagesXMLJavaPlatforms, Frameworks & LibrariesATLMFCSTLWTLCOM / COM+.NET FrameworkWin32/64 SDK & OSVista APIVista SecurityCross PlatformGame DevelopmentMobile DevelopmentWindows CardSpaceWindows Communication FoundationWindows Presentation FoundationWindows Workflow FoundationLibrariesWindows PowershellLINQAzureGeneral ProgrammingAlgorithms & RecipesBugs & WorkaroundsCollectionsCryptography & SecurityDate and TimeDLLs & AssembliesException HandlingLocalisationMacros and Add-insProgramming TipsString handlingInternet / NetworkThreads, Processes & IPCWinHelp / HTMLHelpUncategorised Quick AnswersParallel ProgrammingUncategorised Tips and TricksGraphics / DesignExpressionUsabilityDevelopment LifecycleDebug TipsDesign and ArchitectureInstallationWork IssuesTesting and QACode GenerationGeneral ReadingBook ChaptersBook ReviewsHardware ReviewsInterviewsScrapbookHardware & SystemUncategorised Technical BlogsCodeProject FAQsThird Party ProductsProduct ShowcaseSolution CenterMentor ResourcesAuthor ResourcesServicesProduct CatalogJob BoardCodeProject VS2008 AddinFeature ZonesProduct ShowcaseWhitePapers / Webcasts.NET Dev LibraryASP.NET 4 Web Hosting Advanced Search
Add to IE Search Print Friendly Share Digg Del.icio.us Google Windows Live Technorati Blink Facebook Furl Simpy Reddit Newsvine Stumbleupon Mr. Wong Send as Email Bookmark Discuss Report 6 votes for this article. Popularity: 3.50 Rating: 4.50 out of 5
1
2
3
4
5 Is your email address OK? You are signed up for our newsletters but your email address is either unconfirmed, or has not been reconfirmed in a long time. Please click here to have a confirmation email sent so we can confirm your email address and start sending you newsletters again. Alternatively, you can update your subscriptions.
- Download source code - 1.61 KB
Introduction
LINQ introduced great things to the C# programming language, things that database developers have known for years. In some areas, LINQ goes far beyond what is available from SQL. One example is the group by
clause. In SQL, the result of a group
operation returns a table - nothing else is possible since SQL does not know the notion of classes. In contrast, LINQ's group by
operation can create hierarchical result structures. This article shows how to write a LINQ query using group by
and - even more importantly - demonstrates how you can consume the result in WPF using data binding.
The LINQ Query
In the sample, we assume that we collect status events from programs running on a computer. For every event, we could collect the process ID, a process description (e.g., the file name of the exe), and the event time. The following class acts as a container for events:
Collapse Copy Codepublic class Event{public int PID { get; set; }public string Desc { get; set; }public DateTime EventTime { get; set; }}
The following line of code generates some demo data:
Collapse Copy Codevar data = new List(){new Event() { PID = 1, Desc="Process A", EventTime = DateTime.Now.AddHours(-1) },new Event() { PID = 1, Desc="Process A", EventTime = DateTime.Now.AddHours(-2) },new Event() { PID = 2, Desc="Process B", EventTime = DateTime.Now.AddHours(-3) },new Event() { PID = 2, Desc="Process B", EventTime = DateTime.Now.AddHours(-4) },new Event() { PID = 3, Desc="Process C", EventTime = DateTime.Now.AddHours(-5) }};
As you can see, the master data about the processes is stored multiple times (i.e., the data structure is not in normal form). Our LINQ query should return a hierarchical result in which every process is included only once. Additionally, for every process, we want to have a collection of the corresponding events. The LINQ query solving this problem looks like this:
Collapse Copy Codevar result =from d in datagroup d by new { d.PID, d.Desc } into pgselect new { Process = pg.Key, Items = pg };
Note how the group by
clause is written and how the result (anonymous type) is built. The query groups the result by process ID and process description. Both fields together make up the composite group expression (new { d.PID, d.Desc }
). pg
is of type IGrouping<TKey, TElement>
. TKey
represents the group expression mentioned before. IGrouping
implements IEnumerable
. Therefore, pg
can be used in the select
clause to embed the list of corresponding Event
objects for each group.
Note that the anonymous type for the result contains names for each column (Process = pg.Key, Items = pg
). This is important because without the names, data binding in WPF is much harder (in fact, I do not know whether it is possible without names at all).
Here is how the result looks like in the Visual Studio debugger:
WPF Data Binding
In my example, I want to represent the hierarchical result structure in the user interface, too. Therefore, the following sample should create an expander control for each key. Inside the expander, it should display a listbox with the event details for the corresponding key. Here is a screenshot of the result I want to achieve:
Using data binding to create the expander controls is quite straightforward:
Collapse Copy Code<Window x:Class="WpfApplication5.Window1"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="Window1" Height="300" Width="550"><Grid><ItemsControl x:Name="TopLevelListBox" ItemsSource="{Binding}"><ItemsControl.ItemsPanel><ItemsPanelTemplate><StackPanel Orientation="Horizontal" />ItemsPanelTemplate>ItemsControl.ItemsPanel><ItemsControl.ItemTemplate><DataTemplate><Expander ExpandDirection="Down" Width="175"><Expander.Header><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding Path=Process.PID}" Margin="0,0,5,0"/><TextBlock Text="{Binding Path=Process.Desc}" />StackPanel>Expander.Header>Expander>DataTemplate>ItemsControl.ItemTemplate>ItemsControl>Grid>Window>
As you can see, I use a custom ItemsPanel
to display the expander controls horizontally. The data template converts each result object into the expander control. To make data binding work, we must not forget to set the data context for the ItemsControl
:
var result =from d in datagroup d by new { d.PID, d.Desc } into pgselect new { Process = pg.Key, Items = pg };TopLevelListBox.DataContext = result;
Based on that, we can use the hierarchical result generated by the LINQ query to insert the list of events per expander control, without writing a single line of extra C# code:
Collapse Copy Code<Window x:Class="WpfApplication5.Window1"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="Window1" Height="300" Width="550"><Grid><ItemsControl x:Name="TopLevelListBox" ItemsSource="{Binding}"><ItemsControl.ItemsPanel><ItemsPanelTemplate><StackPanel Orientation="Horizontal" />ItemsPanelTemplate>ItemsControl.ItemsPanel><ItemsControl.ItemTemplate><DataTemplate><Expander ExpandDirection="Down" Width="175"><Expander.Header><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding Path=Process.PID}" Margin="0,0,5,0"/><TextBlock Text="{Binding Path=Process.Desc}" />StackPanel>Expander.Header> <ListBox x:Name="SubListBox" ItemsSource="{Binding Path=Items}"><ListBox.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding Path=EventTime}" />StackPanel>DataTemplate>ListBox.ItemTemplate>ListBox> Expander>DataTemplate>ItemsControl.ItemTemplate>ItemsControl>Grid>Window>
Note that the listbox SubListBox
is bound to Items
. Items
has been defined as a field in the result type of the LINQ query. It contains the list of events corresponding to each group key. By binding like this, we can access the properties of Event
inside the DataTemplate
of the listbox.
Summary
In my opinion, the important takeaways of this sample are:
- LINQ is a powerful tool that is not just useful in combination with databases. It makes it easier to handle in-memory object structures, too.
- LINQ queries can create more complex result structures than SQL.
- WPF data binding works great with LINQ results, even with hierarchical result structures.
Reply·Email·View Thread·PermaLink·Bookmark Rate this message: 1 2 3 4 5 good Zajda82 15:49 15 Oct '08 Nice idea for an article Rainer. You got my 5, keep going.
Reply·Email·View Thread·PermaLink·Bookmark 5.00/5 (1 vote) Rate this message: 1 2 3 4 5 Last Visit: 9:00 6 Jun '10 Last Update: 10:39 6 Jun '10 1
General News Question Answer Joke Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+PgUp/PgDown to switch pages.
PermaLink | Privacy | Terms of UseLast Updated: 14 Oct 2008
Editor: Smitha Vijayan
Copyright 2008 by r.stropek
Everything else Copyright © CodeProject, 1999-2010
Web22 | Advertise on the Code Project