Search code examples
c#wpfxamlmvvmdatatrigger

DataGrid Textbox DataTrigger Condition Not Working As Expected


I have a window that has datagrid populated from datasource. I'm using DataGridTemplateColumn and has textbox. I want to make this textbox read only based on my DrawingType property value. Let's say I have this editable textbox from "Line From X" column. This is only editable if the DrawingType is "Line". My datatrigger condition works fine on window load. However I have issue on new item added on the grid. When I select Ellipse from DrawingType combobox, the textbox "Line From X" should be read only. However I can still input some texts. But when I leave the focus cursor let's say focus to other cells, it's now the time that the newly added item "Line From X" becomes read only. Please help. Here's what I want to achieve.

  1. Make the target textboxes read only whether data came from datasource or newly added. The read only must be evaluated immediately during selection of DrawingType property. I'm using DataTrigger but if other approach can be done, that's okay.
  2. Make the style generic since I'll be applying it to 2 or more columns. I'll convert other columns to DataGridTemplateColumn and add textboxes too using the same datatrigger.

Here's my code and screenshots.

XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"></RowDefinition>
        <RowDefinition Height="35"></RowDefinition>
    </Grid.RowDefinitions>

    <DataGrid ItemsSource="{Binding DrawnObjects}" AutoGenerateColumns="False"  Grid.Row="0" Margin="0,20" Name="dgBldgDrawings" CanUserAddRows="False" IsEnabled="{Binding IsManuallyAdded,Converter={StaticResource VisibilityConverter}}">
        <DataGrid.Columns>
            <DataGridComboBoxColumn ItemsSource="{x:Static ext:Extensions.GetEnumTypes}" SelectedItemBinding="{Binding DrawingType}"  Width="85" Header="Drawing Type">
                <DataGridComboBoxColumn.CellStyle>
                    <Style TargetType="DataGridCell">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding IsManuallyAdded}" Value="False">
                                <Setter Property="IsEnabled" Value="False" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </DataGridComboBoxColumn.CellStyle>
            </DataGridComboBoxColumn>
            <DataGridTextColumn Width="60" Header="X" Binding="{Binding Path=FootX}"/>
            <DataGridTextColumn Width="65" Header="Y" Binding="{Binding Path=FootY}"/>
            <DataGridTextColumn Width="65" Header="Width" Binding="{Binding Path=FootWidth}"/>
            <DataGridTextColumn Width="65" Header="Height" Binding="{Binding Path=FootHeight}"/>
            <DataGridTextColumn Width="65" Header="Text" Binding="{Binding Path=Text}"/>
            <DataGridTemplateColumn Width="80" Header="Line From X">
                <DataGridTemplateColumn.CellTemplate >
                    <DataTemplate >
                        <TextBox Text="{Binding LineFootX1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="16">
                            <TextBox.Style>
                                <Style TargetType="TextBox">
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding Path=DrawingType,UpdateSourceTrigger=PropertyChanged}" Value="Line">
                                            <Setter Property="IsReadOnly" Value="False" />
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </TextBox.Style>
                        </TextBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Width="80" Header="Line From Y" Binding="{Binding Path=LineFootY1}"/>
            <DataGridTextColumn Width="70" Header="Line To X" Binding="{Binding Path=LineFootX2}"/>
            <DataGridTextColumn Width="70" Header="Line To Y" Binding="{Binding Path=LineFootY2}"/>
        </DataGrid.Columns>
        <DataGrid.RowStyle>
            <Style TargetType="{x:Type DataGridRow}">
                <Setter Property="Visibility" Value="{Binding IsForManualDraw, Converter={StaticResource VisibilityConverter}}"/>
            </Style>
        </DataGrid.RowStyle>
        <DataGrid.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black"/>
        </DataGrid.Resources>
    </DataGrid>
    <Button Content="Add New Drawing" Width="150" Command="{Binding AddNewDrawingCommand}" Height="25" Grid.Row="1" Margin="0,0,250,0"/>
    <Button Content="Save" Width="75" Command="{Binding SaveDrawingChangesCommand}" Height="25" Grid.Row="1"/>
    
</Grid>

Screenshots: Working on window load

Not working. I'm still able to input text. It becomes read only when I leave the editing focus


Solution

  • Add another DataTrigger to work if the row is newly added. Based on your posted code it seems that IsManuallyAdded property represents if a new row is added during session.

    <Style TargetType="TextBox">
         <Setter Property="IsReadOnly" Value="False" />
         <Style.Triggers>
                <DataTrigger Binding="{Binding Path=DrawingType,UpdateSourceTrigger=PropertyChanged}" Value="Line">
                      <Setter Property="IsReadOnly" Value="False" />
                 </DataTrigger>
                 <DataTrigger Binding="{Binding IsManuallyAdded}" Value="True">
                      <Setter Property="IsReadOnly" Value="True" />
                  </DataTrigger>
          </Style.Triggers>
    </Style>
    

    Or you can bind it to IsManuallyAdded as shown below:

    <Style TargetType="TextBox">
         <Setter Property="IsReadOnly" Value="{Binding IsManuallyAdded}" />
         <Style.Triggers>
                <DataTrigger Binding="{Binding Path=DrawingType,UpdateSourceTrigger=PropertyChanged}" Value="Line">
                      <Setter Property="IsReadOnly" Value="False" />
                 </DataTrigger>
          </Style.Triggers>
    </Style>
    

    For #2, you can take the style and defined in the resources with the key like <Style TargetType="TextBox" x:Key="MyKey"> and later can apply this on Textbox like

    <TextBox Style={StaticResource MyKey} ..... />