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.

#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.


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));

(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;


//Column Header Colors

To Set the Selected Row, set the DataGrid's Selected Index:
masterDetail.SelectedIndex = 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.CommonExt.RemoveAll(theDataGrid); //Clear Grid


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:
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();
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:
    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


No comments yet.