WPF - How to bind a DataGridTemplateColumn

2020-05-26 07:36发布

问题:

I am trying to get the name of the property associated with a particular DataGridColumn, so that I can then do some stuff based on that. This function is called when the user clicks context menu item on the column's header...

This is fine for the out-of-the-box ready-rolled column types like DataGridTextColumn, since they are bound, but the problem is that some of my columns are DataGridTemplateColumns, which are not bound.

private void GroupByField_Click (object sender, RoutedEventArgs e){
        MenuItem mi = (MenuItem)sender;
        ContextMenu cm = (ContextMenu) mi.Parent;
        DataGridColumnHeader dgch = (DataGridColumnHeader) cm.PlacementTarget;  
        DataGridBoundColumn dgbc = (DataGridBoundColumn) dgch.Column;
        Binding binding = (Binding) dgbc.Binding;
        string BoundPropName = binding.Path.Path;

        //Do stuff based on bound property name here...
    }

So, take for example my Name column... it's a DataGridTemplateColumn (since it has an image and some other stuff in there). Therefore, it is not actually bound to the 'Name' property... but I would like to be, so that the above code will work.

My question is two-part, really:

  1. Is it possible to make a DataGridTemplateColumn be BOUND, so that the above code would work? Can I bind it somehow to a property?

  2. Or do I need to something entirely different, and change the code above?

Thanks in advance!

AT

回答1:

Although you can't bind a template column, you can bind one of the controls held in that column. This is how I solved a similar problem:

<DataGridTemplateColumn Header="ColumnHeader">
     <DataGridTemplateColumn.CellTemplate>
           <DataTemplate>
                 <local:CustomisedUIElement Text="{Binding Path=PropertyToBindTo}"/>
           </DataTemplate>
     </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

If I've understood the initial example properly, this would mean changing the logic of the GroupByField_Click() method to check whether the sending column was a template column and then looking at the elements it contained to obtain the Binding object.



回答2:

For me, ClipboardContentBinding of DataGridTemplateColumn is a solution:

Private Function FindBoundProperty(ByVal col As DataGridColumn) As String

    Dim boundColumn As DataGridBoundColumn = TryCast(col, DataGridBoundColumn)
    Dim boundPropertyName As String = ""
    Dim binding As Binding
    If col.DependencyObjectType.Name = "DataGridTextColumn" Then
        binding = TryCast(boundColumn.Binding, Binding)
        boundPropertyName = binding.Path.Path
    End If
    If col.DependencyObjectType.Name = "DataGridTemplateColumn" Then
        binding = TryCast(col.ClipboardContentBinding, Binding)
        boundPropertyName = binding.Path.Path
    End If
    Return boundPropertyName

End Function


回答3:

It's a tricky one. We achieved the binding by traversing to its grandparent UserControl (we had DataGrid inside a UserControl) and the UserControl was bound to a Presenter (Model in our case). In the code below, check the property SelectedItem of AutoCompleteBox placed inside the DataGridTemplateColumn.

<wpfToolkit:DataGridTemplateColumn  Header="{x:Static resources:Store.ItemNameC}" Width="0.60*">
  <wpfToolkit:DataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate>
        <extended:HOAutoCompleteBox
                            IsTextCompletionEnabled ="True"
                            x:Name="ItemAutoCompleteBox"
                            Populating="ItemAutoCompleteBox_Populating"
                            DefaultType="HealthObject.ObjectModel.pSearchStockItemResult,HealthObject.ObjectModel"
                            Text="{Binding Path= ItemName, Mode=TwoWay}" 
                            <!--- **** HERE IS THE BINDING SAMPLE *****-->
            SelectedItem="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},  Path=Model.SelectedStockItem, Mode=TwoWay}">
        </extended:HOAutoCompleteBox>
    </DataTemplate>
  </wpfToolkit:DataGridTemplateColumn.CellEditingTemplate>

</wpfToolkit:DataGridTemplateColumn>


回答4:

You may use dgbc.ClipboardContentBinding;



回答5:

  1. No, because DataGridTemplateColumn doesn't inherit from DataGridBoundColumn, so the cast to DataGridBoundColumn would fail.
    To make above code work all of your columns must inherit from DataGridBoundColumn abstract class. So making custom derived Column classes instead of DataGridTemplateColumn should work.

  2. You could simply populate a

    Dictionary<DataGridColumn, string> BoundPropName;

    on initialization and then do

    var propName = BoundPropName[dgch.Column]