DataGrid

DataGrid.png

The DataGrid may display rows containing multiple Composites. Typically, there will be one Composite in each cell. Each Composite may in turn have multiple children, such as Labels in a Stack Panel as shown in the example pic above.

SPECIAL NOTES
#1 I could be wrong, but I believe at this time (despite the example given here) that each Composite in a Row must have the same number of child elements. "Jagged" rows with one cell that has three textblocks and another cell that has only two textblocks may likely cause issues? A likely workaround in this example is just to add an extra, empty textblock to the second cell/composite (to even them up.)

#2 It seems that when you add so many columns that a Horizontal scrollbar is required, when you horizontally scroll and then scroll back, the screen fails to repaint some of the grid cells.
(8/31/2014 - Microsoft may have fixed this. I haven't seen this happening lately.)

I'm not sure the cause of this #2. For the time being, either make the grid large enough to avoid scrolling, provide a means to call datagrid.Refresh() to reset the datagrid--although this takes time and you lose your place in the grid, or else use the free Extended WPF Toolkit™ Community Edition DataGrid instead? I am investigating this issue further . . .
(4/29/2014-I have just noticed that re-sizing the columns will repaint those affected cells as long as you then call UpdateLayout();)

In WPF Composites, a DataGridRow stores a single Item of Type ColumnContent<Border, Border, Border, Border, Border, Border, Border, Border, Border, Border, Border>. This custom Type houses a ContentControl for each Cell and within the Content property of each ContentControl, it stores a Border.

HOW TO

To Get the Selected DataGrid Row, in this example, in which the row happens to contain only two columns each with its ContentControl, I extract from each of these ContentControls a respective Border framework element. Each Border is itself an IParent in which children may have been added, and so I get handles to each child Text Block and extract the text out to potentially do something with it:
DataGridRow selectedRow = masterDetail.GetSelectedRow();
if (selectedRow != null)
{
          var cells = selectedRow.Item as ColumnContent<Border, Border, Border, Border, Border, Border, Border, Border, Border, Border, Border>;
          Border contentAtCol0 = cells.Content0.Content as Border;
          Border contentAtCol1 = cells.Content1.Content as Border;

          string flight = contentAtCol0.GetChildFromComposite<TextBlock, DataGrid>(0, 1).GetText();
          string parking = contentAtCol1.GetChildFromComposite<TextBlock, DataGrid>(0, 0).GetText();
     . . . . . . .

I mention the above just to provide a foundation for understanding how the DataGrid works with WPF Composites. As you can see, it is purposely limited to just a relatively reasonable 11 columns (but since the code is open-source, one could easily add on support for more columns, I believe, if desired.)

To Initialize and Add Settings, start by initializing it that same way as you would any IParent, and by choosing a Composite container type to place in the Borders of the cells. In this case, I've chosen a VerticalPanel. Then, add your settings and apply colors to the Scroll Bar as desired. Finally, define the titles for your Column Headers. See example below:
DataGrid masterDetail = new DataGrid();

masterDetail.Initialize(397D, 810D, ContainerType.VerticalPanel, Brushes.WhiteSmoke, Brushes.Gray, Brushes.Gray, new Thickness(0));

masterDetail.BeginSettings().SetBackgroundColorOnItemsControl
(Brushes.LightSlateGray).SetItemBorderColorAndThickness(Brushes.LightSteelBlue, new Thickness(0)).Set<TextBlock, DataGrid>("Padding", new Thickness(2,0,2,0)).SetTextColor(0, 1, Brushes.Black).EndSettings();

masterDetail.BorderBrush = Brushes.Black;
masterDetail.BorderThickness = new Thickness(0);
        
ContemporaryStyle.ApplyToScrollViewer(masterDetail, "LightSteelBlue", "LightSkyBlue", "#FF002050");

List<string> columnHeaderList = new List<String>();
            columnHeaderList.Add(" Attractions");
            columnHeaderList.Add(" Parking Garage");

You may leverage the method ApplyDataGridStrategy to set DataGrid properties such as RowHeaderWidth, SelectionMode, SelectionUnit, RegularRowColor, SelectedContentControlColor, SelectedContentControlForeground, SelectedFocusBorder:
masterDetail.ApplyDataGridStrategy(20, DataGridSelectionMode.Single, DataGridSelectionUnit.FullRow, Brushes.LightSteelBlue, Brushes.LightSkyBlue, Brushes.Black, Brushes.LightSkyBlue, "Gray", "Silver", "1,1,1,1", 1D, "Gray", "Silver", "Gray", "LightSkyBlue", "Gray");

To Add a DataGrid Row, add child Composites for each column of the DataGrid.
NOTE: you need only pass in the columnHeaderList as a parameter to DataGridArgs; for example, you may do this in the first Composite added (yet, it doesn't hurt anything, if you pass it in more than once):

//NOTE: y/column is the index for StackPanel. x/row is ignored.
//add column header list when adding the first composite  

//Column 1
var borderA = masterDetail.BeginComposite<DataGrid>(trav.ID + "1")
                            .AddText(0, 0, trav.Counter.ToString())
                            .AddText(0, 1, "Flight: " + trav.Flight)
                            .AddText(0, 2, "Hotel: " + trav.Hotel)
                            .AddText(0, 3, "Attraction: " + trav.Attraction)
                            .SetMouseOverColorOnContainer<StackPanel, DataGrid>(Brushes.Silver)
                            .EndComposite<DataGrid, DataGridArgs>(new DataGridArgs(trav.ID, 0, 0, columnHeaderList));

//Column 2
masterDetail.BeginComposite<DataGrid>(trav.ParkingGarages[0].ID + "2")
                            .AddText(0, 0, "Color: " + trav.ParkingGarages[0].Color)
                            .AddText(0, 1, "Description: " + trav.ParkingGarages[0].Description)
                            .AddText(0, 2, " ")
                            .SetMouseOverColorOnContainer<StackPanel, DataGrid>(Brushes.Silver)
                            .EndComposite<DataGrid, DataGridArgs>(new DataGridArgs(trav.ParkingGarages[0].ID, 0, 1, columnHeaderList));                         

masterDetail.UpdateByKey<TextBlock, DataGrid>(borderA.GetKey(), 0, 0, txt => { txt.FontWeight = FontWeights.Bold; });

Once the columnHeaderList has been passed in, you may then access these columns to set properties on them such as Minimum Width, Background Color, and Foreground Color:
//set column setting after column header list has been added
masterDetail.Columns[0].MinWidth = 100D;
masterDetail.Columns[1].MinWidth = 90D;

masterDetail.SetBackgroundColor(BrushExt.CreateSolidColorBrushFromString("#FF002050"));

//Column Header Colors
masterDetail.SetColumnHeaderForeground(Brushes.White);
masterDetail.SetColumnHeaderColor(BrushExt.CreateSolidColorBrushFromString("#FF002050"));

To Set the Selected Row, set the DataGrid's Selected Index:
masterDetail.SelectedIndex = 0;
masterDetail.ScrollIntoView(masterDetail.Items[0]);

To Remove a DataGrid Row, unsubscribe child events (if needed) and remove all CHILD COMPOSITES for that row. Once the last Child Composite is removed the entire row will automatically be removed.
            //Example removing a row that contains two child composites
            theDataGrid.UnsubscribeChildEventsByKey(rowGuid + "1");
            theDataGrid.UnsubscribeChildEventsByKey(rowGuid + "2");
            theDataGrid.RemoveByKey(rowGuid + "1");
            theDataGrid.RemoveByKey(rowGuid + "2");

To Remove All DataGrid Rows, unsubscribe all child events recursively (if needed) via DisposeEventsOnAllParents and remove all rows via RemoveAll. (This may be useful if maintaining a separate collection in the background. You may want to perform a remove all and then re-add all to the UI from scratch every time you perform a create, update, or delete? . . . if you are sorting in the background collection or making a roundtrip back to a database? Just another option?)
      FasterWPF.Selectors.DisposeEventsOnAllParents(theDataGrid);
      FasterWPF.CommonExt.RemoveAll(theDataGrid); //Clear Grid

Caveat

The DataGrid support is for Composites in a DataGrid at this time.

For a regular DataSet, in contrast, I merely provide basic examples using the free, open-source DataGrid available from the Extended WPF Toolkit™ Community Edition DataGrid here: http://wpftoolkit.codeplex.com/
In other words, the cells in a DataSet-based DataGrid are NOT considered "composites" but atomic values. The DataGrid itself could be added to a Composite such as it is added to a StackPanel in a TabControl in the Demo App. It is convenient to use this separate DataGrid for this purpose since it resides in a separate namespace.

NOTE: 12/29/2013 *******************************************
Also see WPF Composites Contrib on codeplex.

NOTE: 11/3/2013 *********************************************************
After adding a row, you may need to refresh like so: System.Windows.Data.CollectionViewSource.GetDefaultView(theDataGrid.ItemsSource).Refresh();
NOTE: IN VERSION 5.0, YOU MAY SIMPLY CALL REFRESH on the DATAGRID PARENT
UpdateLayout may also work in certain scenarios.

Also, you may likely need to turn off Virtualization since WPF-CPS works in a simplistic manner, removing all composites and re-adding all composites whenever sorting or filtering:
NOTE: THIS WILL LIKELY BE MADE AUTOMATIC IN VERSION 5.0 . . .
EXAMPLE CODE IN F#:
    let mutable masterDetail = new DataGrid()
    let factory:FrameworkElementFactory = new FrameworkElementFactory(typeof<StackPanel>)
    factory.SetValue(VirtualizingStackPanel.IsVirtualizingProperty, false)   
    masterDetail.SetValue(VirtualizingStackPanel.IsVirtualizingProperty, false)   
    masterDetail.ItemsPanel<-new ItemsPanelTemplate(factory)

Last edited Aug 31, 2014 at 10:52 PM by stagathome0069, version 44

Comments

No comments yet.