/// <summary> /// Create a visual element based on the properties of the column. /// </summary> /// <param name="columnViewColumn">The column that defines the cell.</param> /// <returns>A visual element that holds the content of the cell.</returns> public static FrameworkElement CreateCell(ColumnViewColumn columnViewColumn) { // Validate the parameters. if (columnViewColumn == null) { throw new ArgumentNullException("columnViewColumn"); } // This will either create an element based on the templates associated with the ColumnViewColumn, or for simple binding, will create a simple cell and // bind it using the binding provided in the DisplayMemberBinding property. Both variations return a FrameworkElement that is used as an element in the // row to display the data associated with the column. FrameworkElement frameworkElement; if (columnViewColumn.DisplayMemberBinding == null) { // This will create a generic ContentPresenter using the templates associated with the ColumnView and bind the content of the generic control to // the data context (which contains the row data). It is the responsibility of the cell to select which property of the row data it wants to // display. It is important to remember that a ContentPresenter is not like other controls. The DataContext is not inheritied from the logical // parent, it is set to the Content property of the ContentPresenter. The main problem we're solving here is that the child control that's // generated from the ContentPresenter's template needs a DataContext, but the ContentPresenter doesn't have one since it's pointing to itself. To // solve this, we'll bind the Content of the ContentPresenter to the ColumnViewRowPresenter that is it's parent. This effectively restores the // DataContext inheritance that all other controls have. Clear as mud? ContentPresenter contentPresenter = new ContentPresenter(); contentPresenter.ContentTemplate = columnViewColumn.CellTemplate; contentPresenter.ContentTemplateSelector = columnViewColumn.CellTemplateSelector; Binding dataContextBinding = new Binding() { Path = new PropertyPath("DataContext") }; dataContextBinding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(ColumnViewRowPresenter), 1); BindingOperations.SetBinding(contentPresenter, ContentPresenter.ContentProperty, dataContextBinding); frameworkElement = contentPresenter; } else { // This will create a cell to display the data provided by the 'DisplayMemberBinding' which selects which property of the row data is to be // displayed. ColumnViewColumnCell columnViewColumnCell = new ColumnViewColumnCell(); BindingOperations.SetBinding(columnViewColumnCell, ColumnViewColumnCell.ContentProperty, columnViewColumn.DisplayMemberBinding); frameworkElement = columnViewColumnCell; } // This element is used to present the data. return(frameworkElement); }
/// <summary> /// Handles a change to the column property. /// </summary> /// <param name="sender">The Object that originated the event.</param> /// <param name="propertyChangedEventArgs">The event arguments.</param> protected override void OnColumnPropertyChanged(Object sender, PropertyChangedEventArgs propertyChangedEventArgs) { // Validate the parameters. if (sender == null) { throw new ArgumentNullException("sender"); } if (propertyChangedEventArgs == null) { throw new ArgumentNullException("propertyChangedEventArgs"); } // This will get the column where the property change occurred from the sender. ColumnViewColumn columnViewColumn = sender as ColumnViewColumn; // If the column is visible, then it has a visual element which needs to have its properties reconciled with the ColumnViewColumn properties. if (columnViewColumn.IsVisible) { // This will find the visual element what has properites that must be reconciled with the header. Int32 columnIndex = this.Columns.IndexOf(columnViewColumn); ColumnViewColumnCell columnViewColumnCell = this.Children[columnIndex] as ColumnViewColumnCell; // This will apply the property in the column to the visual element representing that column in the current row. switch (propertyChangedEventArgs.PropertyName) { case "CellTemplate": case "CellTemplateSelector": case "DisplayMemberBinding": // Recreate the cell based on the new properties. this.Children.RemoveAt(columnIndex); FrameworkElement frameworkElement = ColumnViewRowPresenter.CreateCell(columnViewColumn); this.InstallCell(frameworkElement, columnViewColumn); this.Children.Insert(columnIndex, frameworkElement); break; case "Width": case "MinWidth": // Forcing a re-measurement of the row will pick up the changes made to the column's width. this.InvalidateMeasure(); break; } } }