31

If I create a binding to the IsReadOnly property of the DataGridTextColumn, it does not actualize. If I set it through markup, it works.

<DataGridTextColumn IsReadOnly="{Binding IsReferenceInactive}"/> <!-- NOP --> 

<DataGridTextColumn IsReadOnly="True"/> <!-- Works as expected, cell is r/o -->

The IsReferenceInactive property is a DP and works fine (For testing purposes I've bound it to a checkbox, that worked)

Is this a known limitation?

Update

Uups, other than I wrote, there is a message in the output window:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=IsReferenceInactive; DataItem=null; target element is 'DataGridTextColumn' (HashCode=23836176); target property is 'IsReadOnly' (type 'Boolean')

HCL
  • 36,053
  • 27
  • 163
  • 213
  • It seems that link to Microsoft Connect in Update section has been retired since january 2022. Please, update or remove the link. – Andark Jun 02 '22 at 05:29

7 Answers7

38

Same as codekaizen but simpler:

<DataGridTextColumn>
  <DataGridTextColumn.CellStyle>
    <Style>
      <Setter Property="UIElement.IsEnabled" Value="{Binding IsEditable}" />
    </Style>
  </DataGridTextColumn.CellStyle>
</DataGridTextColumn>
hansmaad
  • 18,417
  • 9
  • 53
  • 94
  • This is the best (and should marked as the Accepted) Answer, since it: a) maintains original display/editing formats, b) not specific to display and editing sub-Elements *and* c) is the simplest! – Tom Apr 25 '19 at 00:50
  • 3
    The `UIElement.IsEnabled` also makes the cell unselectable, meaning that such columns cannot be naviaged on keyboard and their values cannot be copied to clipboard. – wondra Oct 23 '19 at 12:03
18

DataGridColumns are not part of the visual tree, and don't participate in binding like this. The way I get around it is to use DataGridTemplateColumn.

<DataGridTemplateColumn>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=myProperty}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <TextBox IsEnabled="{Binding Path=myBool}" Text="{Binding Path=myProperty, Mode=TwoWay}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

There are other workarounds, which I've found a bit too hackish, but they do work; to wit: Link

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
codekaizen
  • 26,990
  • 7
  • 84
  • 140
  • Ok, eventually I remarked it also. I have not looked good enough in the output window. Sorry, I posted to fast. But I dont't will delete the question, perhaps it will help someone who also was in a hurry:) – HCL Jul 11 '10 at 11:27
  • 1
    No problem; it gives more fodder for Google/Bing to find the right answer when questions are asked on SO. – codekaizen Jul 11 '10 at 11:29
  • @hansmaad's Answer (at " https://stackoverflow.com/a/18657986/401246 ") is the best (and should marked as the Accepted) Answer, since it: a) maintains original display/editing formats, b) is not specific to display and editing sub-Elements *and* c) is the simplest! – Tom Apr 25 '19 at 00:52
8

I found this solution which allows you to bind to data when the DataContext is not inherited: http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/

Add the BindingProxy class Thomas wrote and add this resource to your DataGrid:

<DataGrid.Resources>
    <local:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>

Now you can bind to your DataContex via the Data property of the BindingProxy just as you would expect.

<DataGridTextColumn Header="Price"
                    Binding="{Binding Price}"
                    IsReadOnly="{Binding Data.LockFields, Source={StaticResource proxy}}"/>
Ryan Mathewson
  • 141
  • 2
  • 4
0

The Binding of the DataGridTextColumn works only for the Text property, but not for the other properties of DataGridTextColumn.

Solution: DataGridTextColumn tells the DataGrid to create a TextBlock for every row and that column. You can define a style for TextBlock and link the Style with the Style.Key to the TextBlock of that column (ElementStyle).

Of course, the TextBlock needs now to find the object from the datalist. It can do that with a RelativeSource Binding with the AncestorType=DataGridRow. The DataGridRow then provides access to the object.

Something like this:

<Window.Resources>
  <Style x:Key="IsReadOnlyStyle" TargetType="TextBlock">
    <Setter Property="IsReadOnly" 
      Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, 
      Path =Item.NoOutput/>
  </Style>
</Window.Resources>

<DataGrid>
  <DataGrid.Columns>
    <DataGridTextColumn Header="Value" Width="*" Binding="{Binding Value}" ElementStyle="{StaticResource IsReadOnlyStyle}"/>
</DataGrid.Columns>

Complicated right ? I recommend you to read my detailed article about datagrid formatting at: http://www.codeproject.com/Articles/683429/Guide-to-WPF-DataGrid-formatting-using-bindings?msg=5037235#xx5037235xx

Good luck, you need it :-)

Peter Huber
  • 3,052
  • 2
  • 30
  • 42
  • 1
    This solution does not work. TextBlock does not have an IsReadOnly property. TextBox has that property, but it can only be used with EditingElementStyle, which produces visually different results. – Philip Atz Oct 15 '15 at 12:51
0

If you like @codekaizen's solution but will have the look of a disabled TextBox, then this will do the trick:

<DataGridTemplateColumn>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBox IsEnabled="{Binding Path=myBool}" Text="{Binding Path=myProperty}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <TextBox IsEnabled="{Binding Path=myBool}" Text="{Binding Path=myProperty, Mode=TwoWay}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
Rolf
  • 1,219
  • 2
  • 13
  • 23
0

I've found a nice solution to use DataGridColumns with binding by using a MarkupExtension. This way Bindings with converters could be used: https://stackoverflow.com/a/27465022/9758687

Coden
  • 2,579
  • 1
  • 18
  • 25
0

If you've used EditingElementStyle and need to change IsEnabled value by Binding:

    <DataGridTextColumn
        MinWidth="100"
        MaxWidth="250"
        Binding="{Binding MessageText, UpdateSourceTrigger=PropertyChanged}"
        ElementStyle="{StaticResource TextBlockStyle}"
        Header="Message Text">
        <DataGridTextColumn.EditingElementStyle>
            <Style BasedOn="{StaticResource TextBoxStyle}" TargetType="TextBox">
                <Setter Property="IsEnabled" Value="{Binding IsEnabledMessage}" />
            </Style>
        </DataGridTextColumn.EditingElementStyle>
    </DataGridTextColumn>
Anri
  • 41
  • 7