Pregunta

Yo entiendo que puede hacer que toda la cuadrícula de datos o una columna entera readyonly (IsReadOnly = true). Sin embargo, a nivel celular esta propiedad sólo está listo. Pero necesito este nivel de granularidad. No es blog sobre la adición de IsReadOnly a una fila cambiando el código fuente en viejos tiempos cuando era cuadrícula de datos de dominio público, pero ahora no tengo el código fuente de cuadrícula de datos. ¿Qué hay solución?

Hacer celular desactivado (IsEnabled = false) casi cubre mis necesidades. Pero el problema es que ni siquiera se puede clic en la celda con discapacidad para seleccionar la fila (no tengo modo de pantalla completa selección de filas).

EDIT: Ya que nadie ha respondido a esta pregunta, así que supongo que no es una solución fácil. He aquí una posible solución: Hacer la celda no editable. El único problema es que la clic en la celda no selecciona la fila. Acabo de notar que MouseDown o MouseUp caso de la cuadrícula de datos todavía está activa cuando se hace clic en la celda con discapacidad. En este controlador de eventos, si pudiera averiguar la fila que se hace clic, pude seleccionar la fila mediante programación. Sin embargo, no pude encontrar la manera de encontrar la fila subyacente de DataGrid.InputHitTest. ¿Puede alguien por favor, dame un poco de punta?

¿Fue útil?

Solución

Me he encontrado con el mismo problema, la célula debe ser de sólo lectura en algunas filas, pero no en los otros. Aquí es una solución de solución:

La idea es cambiar dinámicamente el CellEditingTemplate entre dos plantillas, una es la misma que la de la CellTemplate, el otro es para la edición. Esto hace que el modo de edición actúa exactamente el mismo que el de células no editando aunque está en el modo de edición.

El siguiente es un ejemplo de código para hacer esto, observe que este enfoque requiere DataGridTemplateColumn:

En primer lugar, definir dos plantillas de sólo lectura y edición de células:

<DataGrid>
  <DataGrid.Resources>
    <!-- the non-editing cell -->
    <DataTemplate x:Key="ReadonlyCellTemplate">
      <TextBlock Text="{Binding MyCellValue}" />
    </DataTemplate>

    <!-- the editing cell -->
    <DataTemplate x:Key="EditableCellTemplate">
      <TextBox Text="{Binding MyCellValue}" />
    </DataTemplate>
  </DataGrid.Resources>
</DataGrid>

A continuación, definir una plantilla de datos con capa ContentPresenter adicional y el uso Trigger para cambiar la ContentTemplate de la ContentPresenter, por lo que las dos plantillas anteriores se pueden cambiar dinámicamente por el IsEditable unión:

<DataGridTemplateColumn CellTemplate="{StaticResource ReadonlyCellTemplate}">
  <DataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate>
      <!-- the additional layer of content presenter -->
      <ContentPresenter x:Name="Presenter" Content="{Binding}" ContentTemplate="{StaticResource ReadonlyCellTemplate}" />
      <DataTemplate.Triggers>
        <!-- dynamically switch the content template by IsEditable binding -->
        <DataTrigger Binding="{Binding IsEditable}" Value="True">
          <Setter TargetName="Presenter" Property="ContentTemplate" Value="{StaticResource EditableCellTemplate}" />
        </DataTrigger>
      </DataTemplate.Triggers>
    </DataTemplate>
  </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

HTH

Otros consejos

Después de mucho buscar y experimentación utilizando IsTabStop = False y enfocable = False trabajos mejores para mí.

<DataGridTextColumn Header="My Column" Binding="{Binding Path=MyColumnValue}">
    <DataGridTextColumn.CellStyle>
        <Style TargetType="DataGridCell">                                    
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=ReadOnly}" Value="True">                                                    
                    <Setter Property="IsTabStop" Value="False"></Setter>
                    <Setter Property="Focusable" Value="False"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGridTextColumn.CellStyle>
</DataGridTextColumn>

Hay una propiedad en DataGridCell.IsReadOnly que se podría pensar que puede unirse a,
p.ej. usando XAML como esto:

<!-- Won't work -->
<DataGrid Name="myDataGrid" ItemsSource="{Binding MyItems}">
    <DataGrid.Resources>
        <Style TargetType="DataGridCell">
            <Setter Property="IsReadOnly" Value="{Binding MyIsReadOnly}" />
        </Style>
    </DataGrid.Resources>
    <!-- Column definitions... -->
</DataGrid>

Unfortunantly esto no funcionará porque esta propiedad no se puede escribir.
Luego usted podría intentar interceptar eventos de ratón y parada, pero esto no va a evitar que el usuario entre en el modo de edición utilizando la tecla F2.

La forma en que esto era sloved al detectar los PreviewExecutedEvent en la cuadrícula de datos y luego condicionalmente marcándola como manejada.
P.ej. mediante la adición de código similar al siguiente al constructor de mi ventana o control de usuario (o en otro lugar más adecuado):

myDataGrid.AddHandler(CommandManager.PreviewExecutedEvent,
    (ExecutedRoutedEventHandler)((sender, args) =>
{
    if (args.Command == DataGrid.BeginEditCommand)
    {
        DataGrid dataGrid = (DataGrid) sender;
        DependencyObject focusScope = FocusManager.GetFocusScope(dataGrid);
        FrameworkElement focusedElement = (FrameworkElement) FocusManager.GetFocusedElement(focusScope);
        MyRowItemModel model = (MyRowItemModel) focusedElement.DataContext;
        if (model.MyIsReadOnly)
        {
            args.Handled = true;
        }
    }
}));

Al hacerlo de esta manera las células siguen siendo enfocable y seleccionable.
Sin embargo, el usuario no será capaz de entrar en el modo de edición a menos que sus elementos de modelo permiten que él en la fila dada.
Y no van a sufrir los costes de funcionamiento o complejidades mediante el uso de la DataGridTemplateColumn.

He resuelto este problema en mi aplicación estableciendo el objeto subyacente en la célula (por ejemplo, casilla de verificación.) - IsHitTestVisible = false; Enfocable = false;

var cb = this.dataGrid.Columns[1].GetCellContent(row) as CheckBox;
cb.IsHitTestVisible = false;
cb.Focusable = false;

"fila" es un DataGridRow. IsHitTestVisible = false, significa que no se puede hace clic / Seleccionar / manipular el objeto subyacente a través del ratón, pero todavía se puede seleccionar el DataGridCell. medios enfocable = falsas, que no se puede seleccionar / manipulan el objeto subyacente con el teclado. Esto da la ilusión de una célula de sólo lectura, pero todavía se puede seleccionar la celda y estoy seguro de que si la cuadrícula de datos está configurado para SelectionMode = FullRow a continuación, haga clic en el "sólo lectura" célula seleccionará la totalidad fila.

Mi solución es utilizar la unión al DataGridTemplateColumn con convertidor.

<UserControl.Resources>
    <c:isReadOnlyConverter x:Key="isRead"/>
</UserControl.Resources>

   <DataGridTemplateColumn x:Name="exampleTemplate" Header="example:" Width="120" IsReadOnly="True">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                            <CheckBox x:Name="exampleCheckBox" VerticalAlignment="Center" IsEnabled="{Binding ElementName=exmpleTemplate, Path=IsReadOnly, Converter={StaticResource isRead}}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

y el convertidor:

class isReadOnlyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        try
        {
            return !(bool)value;
        }
        catch (Exception)
        {
            return false;
        }
    }

Sobre la base de comentario @sohum, aquí se puede utilizar la versión simplificada de la respuesta marcada como respuesta.

dataGrid.BeginningEdit += DataGrid_BeginningEdit;

(...)

private static void DataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
{
    //Actual content of the DataGridCell
    FrameworkElement content = e.Column.GetCellContent(e.Row);
    MyObject myObject = (MyObject)content.DataContext;

    if (!myObject.CanEdit)
    {
        e.Cancel = true;
    }
}

Puede utilizarlo más tarde como comportamiento de la propiedad adjunta.

Una forma de conseguir seleccionable, celdas de texto de sólo lectura para la cuadrícula de datos es el uso de la plantilla y el estilo de esta manera:

<DataGrid>
<DataGrid.CellStyle>
    <Style TargetType="{x:Type DataGridCell}">                                        
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridCell}">
                    <Border Padding="0" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                         <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        <TextBox BorderThickness="0" MouseDoubleClick="DataGrid_TextBox_MouseDoubleClick" IsReadOnly="True" Padding="5" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</DataGrid.CellStyle>

Y para CS backend:

private void DataGrid_TextBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        (sender as TextBox).SelectAll();
    }

Esto es un poco tarde, pero, yo estaba buscando en esto así, estas soluciones funcionan bien, pero necesitaba algo un poco diferente, hice lo siguiente y funciona exactamente como yo quería y lo que la pregunta está buscando.

Me esencialmente que quería ser capaz de entrar en el modo de edición para la célula y tienen todo lo que otras plantillas y la lógica de comandos al mismo tiempo no ser capaz de editar la celda.

La solución para todo esto es para establecer la propiedad TextBox.IsReadOnly en true en el estilo DataGridCell y para controlar el evento KeyDown inicial

<Style TargetType="DataGridCell">
    <Setter Property="TextBox.IsReadOnly" Value="True"/>
    <EventSetter Event="PreviewKeyDown" Handler="cell_PreviewKeyDown"/>
</Style>

y el siguiente código detrás para detener la edición inicial

protected void cell_PreviewKeyDown(object sender, KeyEventArgs e)
{
    DataGridCell cell = sender as DataGridCell;
    if (cell.IsEditing == false && 
        ((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.Control)) //So that Ctrl+C keeps working
    {
        cell.IsEditing = true;
        e.Handled = true;
    }
}

Esperamos que esto es útil.

En mi caso yo estaba usando DataGridTextColumn. He establecido la propiedad IsEnabled en ContentPresenter en el estilo de la siguiente manera y funciona bien -

     <DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
        <DataGrid.Resources>
            <Style TargetType="{x:Type DataGridCell}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type DataGridCell}">
                            <Grid Background="{TemplateBinding Background}" >
                                <ContentPresenter IsEnabled="{Binding Path=IsEditable}"/>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </DataGrid.Resources>
        <DataGridTextColumn Header="A" 
                            Binding="{Binding Path=A}"/>
    </DataGrid>

Se puede hacer esto con una plantilla de datos simple.

<DataGrid.Resources>
    <DataTemplate x:Key="MyTemplate" DataType="MyRowDataType">
        <TextBox Text="{Binding Value}" IsReadOnly="{Binding IsReadOnly}" />
    </DataTemplate>
</DataGrid.Resources>

...

<DataGridTemplateColumn CellTemplate="{StaticResource MyTemplate}" />
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top