{"id":2394,"date":"2014-09-28T09:46:59","date_gmt":"2014-09-28T09:46:59","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=2394"},"modified":"2016-08-05T10:42:30","modified_gmt":"2016-08-05T10:42:30","slug":"synchronizing-the-columns-in-hierarchical-in-a-xamdatagrid","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/synchronizing-the-columns-in-hierarchical-in-a-xamdatagrid\/","title":{"rendered":"Synchronizing the columns in hierarchical in a XamDataGrid"},"content":{"rendered":"<p><em>Before I start this post, let me just say I\u2019m using an old version of the Infragistics XamDataGrid for this post, version 10.3. Hence this may have been changed in subsequent releases, but as I have a legacy application to support, that\u2019s the version they\u2019re using.<\/em><\/p>\n<p>If you followed my previous post on using hierarchical data in a XamDataGrid, you&#8217;ll have noticed that the final image was hardly impressive, in that columns were not all in sync and if you resize a column, not all columns resize.<\/p>\n<p>For now, let&#8217;s remove the second FieldLayout&#8217;s hidden field, so our XAML looks like the following (I&#8217;ve commented out the offending line)<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;igDP:XamDataGrid GroupByAreaLocation=&quot;None&quot; DataSource=&quot;{Binding}&quot; Name=&quot;Grid&quot;&gt;\r\n   &lt;igDP:XamDataGrid.FieldLayoutSettings&gt;\r\n      &lt;igDP:FieldLayoutSettings ExpansionIndicatorDisplayMode=&quot;CheckOnDisplay&quot;\r\n                                          AutoGenerateFields=&quot;False&quot;\/&gt;\r\n   &lt;\/igDP:XamDataGrid.FieldLayoutSettings&gt;\r\n   &lt;igDP:XamDataGrid.FieldLayouts&gt;\r\n      &lt;igDP:FieldLayout&gt;\r\n         &lt;igDP:FieldLayout.Fields&gt;\r\n            &lt;igDP:Field Name=&quot;Name&quot; \/&gt;\r\n            &lt;igDP:Field Name=&quot;Manages&quot; Visibility=&quot;Hidden&quot; \/&gt;\r\n         &lt;\/igDP:FieldLayout.Fields&gt;\r\n      &lt;\/igDP:FieldLayout&gt;\r\n\r\n      &lt;igDP:FieldLayout&gt;\r\n         &lt;igDP:FieldLayout.Settings&gt;\r\n            &lt;igDP:FieldLayoutSettings LabelLocation=&quot;Hidden&quot; \/&gt;\r\n         &lt;\/igDP:FieldLayout.Settings&gt;\r\n         &lt;igDP:FieldLayout.Fields&gt;\r\n            &lt;igDP:Field Name=&quot;Name&quot; \/&gt;\r\n            &lt;!-- remove this line for now\r\n            &lt;igDP:Field Name=&quot;DepartmentManages&quot; Visibility=&quot;Hidden&quot; \/&gt;\r\n            --&gt;\r\n         &lt;\/igDP:FieldLayout.Fields&gt;\r\n      &lt;\/igDP:FieldLayout&gt;\r\n\r\n   &lt;\/igDP:XamDataGrid.FieldLayouts&gt;\r\n&lt;\/igDP:XamDataGrid&gt;\r\n<\/pre>\n<p>This will produce the following <\/p>\n<p><img decoding=\"async\" src=\"http:\/\/putridparrot.com\/blog\/wp-content\/uploads\/2014\/09\/XamDataGrid3.png\" alt=\"Columns aligned in parent child relationship\" \/><\/p>\n<p>However, this is an illusion that. All is still not quite as we want &#8211; if we resize the parent then you&#8217;ll see that child columns do not remain in sync with the parent. To handle this, let&#8217;s go back to the XAML and add the following to the XamDataGrid<\/p>\n<p><em>Note: I gave the XamDataGrid the name &#8220;Grid&#8221; as we&#8217;re going to need to write some code for the following changes in functionality.<\/em><\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;igDP:XamDataGrid.Resources&gt;\r\n   &lt;Style TargetType=&quot;{x:Type igDP:LabelPresenter}&quot;&gt;\r\n      &lt;EventSetter Event=&quot;SizeChanged&quot; Handler=&quot;EventSetter_OnHandler&quot;\/&gt;\r\n   &lt;\/Style&gt;\r\n&lt;\/igDP:XamDataGrid.Resources&gt;\r\n<\/pre>\n<p>The EventSetter_OnHandler code looks like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate void EventSetter_OnHandler(object sender, SizeChangedEventArgs e)\r\n{\r\n   var lp = sender as LabelPresenter;\r\n   if (lp != null)\r\n   {\r\n      if (Grid.FieldLayouts&#x5B;0].Fields.Contains(lp.Field))\r\n      {\r\n         var f = Grid.FieldLayouts&#x5B;1].Fields&#x5B;lp.Field.Index];\r\n         f.Width = new FieldLength(lp.Field.CellWidthResolved);\r\n      }\r\n\r\n      if (Grid.FieldLayouts&#x5B;1].Fields.Contains(lp.Field))\r\n      {\r\n         var f = Grid.FieldLayouts&#x5B;0].Fields&#x5B;lp.Field.Index];\r\n         f.Width = new FieldLength(lp.Field.CellWidthResolved);\r\n      }\r\n   }\r\n}\r\n<\/pre>\n<p>Now when you resize the columns all will remain in sync, however as you can see from the code this is all a little nasty in that it&#8217;s very much dependent upon the number of FieldLayouts you have etc.<\/p>\n<p>Let&#8217;s not worry too much about that at the moment. As there&#8217;s something a little more pressing, if you happend to expose multiple columns, for example, suppose I added an age column to the parent and child view models and added the fields to the XAML. When moving a column around you&#8217;ll notice the child will not reorganise it&#8217;s columns, so you&#8217;d end up with, for example &#8211; the parent columns Age followed by Name whereas the child would be Name followed by Age.<\/p>\n<p>To fix this add the following FieldPositionChanged event intot he XamDataGrid<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;igDP:XamDataGrid GroupByAreaLocation=&quot;None&quot; \r\n    DataSource=&quot;{Binding}&quot; \r\n    Name=&quot;Grid&quot; \r\n    FieldPositionChanged=&quot;Grid_OnFieldPositionChanged&quot;&gt; &lt;!-- our new addition --&gt;\r\n<\/pre>\n<p>In the source code we&#8217;d now need to add the following<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate void Grid_OnFieldPositionChanged(object sender, FieldPositionChangedEventArgs e)\r\n{\r\n   if (Grid.FieldLayouts&#x5B;0].Fields.Contains(e.Field))\r\n   {\r\n      foreach (var field in Grid.FieldLayouts&#x5B;0].Fields)\r\n      {\r\n         if (field.Index &lt; Grid.FieldLayouts&#x5B;1].Fields.Count)\r\n         {\r\n            var field2 = Grid.FieldLayouts&#x5B;1].Fields&#x5B;field.Index];\r\n            field2.ActualPosition = new FieldPosition(field.ActualPosition.Column, \r\n                        field.ActualPosition.Row, \r\n                        field.ActualPosition.ColumnSpan, \r\n                        field.ActualPosition.RowSpan);\r\n         }\r\n      }\r\n   }\r\n\r\n   if (Grid.FieldLayouts&#x5B;1].Fields.Contains(e.Field))\r\n   {\r\n      foreach (var field in Grid.FieldLayouts&#x5B;1].Fields)\r\n      {\r\n         var field2 = Grid.FieldLayouts&#x5B;0].Fields&#x5B;field.Index];\r\n         field2.ActualPosition = new FieldPosition(field.ActualPosition.Column, \r\n                     field.ActualPosition.Row, \r\n                     field.ActualPosition.ColumnSpan, \r\n                     field.ActualPosition.RowSpan);\r\n      }\r\n   }\r\n}\r\n<\/pre>\n<p>Notice again we need to have knowledge about the number of field layouts to handle this correctly, but this will now work. Reordering the columns occurs across all rows.<\/p>\n<p>This is not perfect &#8211; and obviously we need to look at rewriting our code to handle any number of FieldLayouts, but it&#8217;s a start. I&#8217;ve more things I need to do with this hierarchical data, so if it&#8217;s interesting enough I&#8217;ll continue with further posts, but for now, between this and the previous post on the subject, we can now display hierarchical data and keep the columns in sync.  <\/p>\n<p><strong>Addendum<\/strong><\/p>\n<p>After writing this post I found a mad desire to rewrite the code to handle multiple FieldLayouts, this has not been tested fully (so use at your own risk) but here goes<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate void EventSetter_OnHandler(object sender, SizeChangedEventArgs e)\r\n{\r\n   var lp = sender as LabelPresenter;\r\n   if (lp != null)\r\n   {\r\n      var found = Grid.FieldLayouts.FirstOrDefault(fl =&gt; fl.Fields.Contains(lp.Field));\r\n      if (found != null)\r\n      {\r\n         foreach (var fl in Grid.FieldLayouts)\r\n         {\r\n            if (!fl.Equals(found))\r\n            {\r\n               var f = fl.Fields&#x5B;lp.Field.Index];\r\n               f.Width = new FieldLength(lp.Field.CellWidthResolved);\t\t\t\t\t\t\t\r\n            }\r\n         }\r\n     }\r\n   }\r\n}\r\n\r\nprivate void Grid_OnFieldPositionChanged(object sender, FieldPositionChangedEventArgs e)\r\n{\r\n   var found = Grid.FieldLayouts.FirstOrDefault(fl =&gt; fl.Fields.Contains(e.Field));\r\n   if (found != null)\r\n   {\r\n      foreach (var field in found.Fields)\r\n      {\r\n         foreach (var fl in Grid.FieldLayouts)\r\n         {\r\n            if (!fl.Equals(found))\r\n            {\r\n               if (field.Index &lt; fl.Fields.Count)\r\n               {\r\n                  var f = fl.Fields&#x5B;field.Index];\r\n                  f.ActualPosition = new FieldPosition(\r\n                       field.ActualPosition.Column, \r\n                       field.ActualPosition.Row, \r\n                       field.ActualPosition.ColumnSpan, \r\n                       field.ActualPosition.RowSpan);\r\n               }\r\n            }\r\n         }\r\n      }\r\n   }\r\n}\r\n<\/pre>\n<p><strong>Update<\/strong><\/p>\n<p>Revisiting this code to use it on a project I&#8217;m working on, I found I&#8217;d missed a piece off. When resizing the columns from the parent\/header this works fine but XamDataGrid allows you to resize the child rows and we don&#8217;t have code to resize the parents and keep in sync. <\/p>\n<p>An easy way to &#8220;fix&#8221; this is to disable resizing on columns except for on the header which we can achieve easily by adding to our grid XAML<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nPreviewMouseMove=&quot;Grid_OnPreviewMouseMove&quot;\r\n<\/pre>\n<p>and in our code behind we have <\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ you'll need this using Infragistics.Windows;\r\nprivate void Grid_OnPreviewMouseMove(object sender, MouseEventArgs e)\r\n{\r\n   var lp = Utilities.GetAncestorFromType(e.OriginalSource as DependencyObject, \r\n                typeof(LabelPresenter), true) as LabelPresenter;\r\n\r\n   if (lp == null)\r\n   {\r\n      var cvp = Utilities.GetAncestorFromType(e.OriginalSource as DependencyObject, \r\n                    typeof(CellValuePresenter), true) as CellValuePresenter;\r\n      if (cvp != null)\r\n      {\r\n         cvp.Field.Settings.AllowResize = false;\r\n      }\r\n   }\r\n   else\r\n   {\r\n      lp.Field.Settings.AllowResize = true;\r\n   }\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Before I start this post, let me just say I\u2019m using an old version of the Infragistics XamDataGrid for this post, version 10.3. Hence this may have been changed in subsequent releases, but as I have a legacy application to support, that\u2019s the version they\u2019re using. If you followed my previous post on using hierarchical [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[84,85],"tags":[],"class_list":["post-2394","post","type-post","status-publish","format-standard","hentry","category-infragistics","category-xamdatagrid"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/2394","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=2394"}],"version-history":[{"count":8,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/2394\/revisions"}],"predecessor-version":[{"id":4213,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/2394\/revisions\/4213"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=2394"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=2394"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=2394"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}