Question

Je comprends que vous pouvez faire tout le DataGrid ou une colonne entière readyonly (IsReadOnly = true). Cependant, au niveau des cellules de cette propriété est prêt seulement. Mais je besoin de ce niveau de granularité. Il y a blog sur l'ajout IsReadOnly à une ligne en modifiant le code source dans les vieux jours où DataGrid était domaine public, mais maintenant je n'ai pas le code source pour DataGrid. Quoi de solution de contournement?

Faire cellule désactivée (IsEnabled = false) presque répond à mes besoins. Mais le problème est que vous ne pouvez même pas cliquer sur la cellule désactivée pour sélectionner la ligne (je complète le mode de sélection de ligne).

EDIT: Puisque personne n'a répondu à cette question, donc je suppose que ce n'est pas une solution facile. Voici une solution possible: Assurez-vous de la cellule non modifiable. Le seul problème est que cliquer sur la cellule ne sélectionne pas la ligne. Je viens de remarquer que l'événement MouseDown ou MouseUp du DataGrid est toujours déclenché lorsque la cellule est désactivé cliqué. Dans ce gestionnaire d'événements, si je pouvais comprendre la ligne il a cliqué, je pouvais sélectionner la ligne d'un programme. Cependant, je ne pouvais pas comprendre comment trouver la ligne sous-jacente de DataGrid.InputHitTest. Quelqu'un peut-il s'il vous plaît me donner un pourboire?

Était-ce utile?

La solution

Je l'ai rencontré le même problème, la cellule doit être en lecture seule dans certaines lignes, mais pas dans les autres. Voici une solution de contournement:

L'idée est de changer dynamiquement le CellEditingTemplate entre deux modèles, l'un est le même que celui du CellTemplate, l'autre pour l'édition. Cela rend le mode d'édition agit exactement la même que la cellule non-édition bien qu'il soit en mode édition.

Voici certains exemples de code pour ce faire, un avis que cette approche nécessite DataGridTemplateColumn:

Tout d'abord, définir deux modèles pour en lecture seule et les cellules d'édition:

<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>

Définissez ensuite un modèle de données avec couche ContentPresenter supplémentaires et l'utilisation Trigger pour changer le ContentTemplate du ContentPresenter, de sorte que les deux modèles ci-dessus peuvent être activés dynamiquement par le IsEditable de liaison:

<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

Autres conseils

Après beaucoup de recherche et d'expérimentation en utilisant IsTabStop = False et Focusable = œuvres Faux mieux pour moi.

<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>

Il y a une propriété sur DataGridCell.IsReadOnly que vous pourriez penser que vous pouvez lier à,
par exemple. en utilisant XAML comme ceci:

<!-- 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 cela ne fonctionnera pas parce que cette propriété est en lecture seule.
Ensuite, vous pouvez tenter d'événements d'interception et de la souris d'arrêt, mais cela n'empêche pas l'utilisateur d'entrer dans le mode d'édition en utilisant la touche F2.

La façon dont je sloved ce fut en écoutant le PreviewExecutedEvent sur le DataGrid, puis comme condition signalant manipulé.
Par exemple. en ajoutant du code similaire à celui au constructeur de ma fenêtre ou UserControl (ou un autre endroit plus approprié):

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;
        }
    }
}));

En faisant comme cela, les cellules sont encore focalisable et sélectionnables.
Mais l'utilisateur ne sera pas en mesure d'entrer en mode d'édition à moins que vos éléments de modèle lui permettent de la ligne donnée.
Et vous ne souffrirez pas les coûts de la performance ou la complexité en utilisant le DataGridTemplateColumn.

Je l'ai résolu ce problème dans mon application en définissant l'objet sous-jacent dans la cellule (par exemple CheckBox.) - IsHitTestVisible = false; Focusable = false;

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

"ligne" est un DataGridRow. IsHitTestVisible = false, signifie que vous ne pouvez pas cliquez sur / select / manipuler l'objet sous-jacent à la souris, mais vous pouvez toujours sélectionner le DataGridCell. Vario = faux, signifie que vous ne pouvez pas sélectionner / manipuler l'objet sous-jacent avec le clavier. Cela donne l'illusion d'une cellule ReadOnly, mais vous pouvez toujours sélectionner la cellule et je suis sûr que si le DataGrid est configuré pour SelectionMode = FullRow en cliquant sur la cellule « lecture seule » sélectionnera l'ensemble rangée.

Ma solution est d'utiliser la liaison à l'DataGridTemplateColumn avec convertisseur.

<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>

et le convertisseur:

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

Sur la base de commentaires @sohum, ici vous pouvez utiliser la version simplifiée de la réponse marquée comme réponse.

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;
    }
}

Vous pouvez l'utiliser plus tard comme comportement Propriété Attached.

Une façon de sélectionner, en lecture seule des cellules de texte pour DataGrid est d'utiliser le modèle et le style comme ceci:

<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>

Et pour backend CS:

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

Ceci est un peu en retard, mais je cherchais dans ce ainsi, ces solutions fonctionnent bien mais je besoin de quelque chose d'un peu différent, je l'ai fait ce qui suit et il fonctionne exactement comme je voulais et ce que la question est à la recherche.

Je voulais essentiellement je être en mesure d'entrer dans le mode d'édition pour la cellule et ont tout ce que d'autres modèles et la logique de commande même sans pouvoir modifier la cellule.

La solution pour tout cela est de définir la propriété TextBox.IsReadOnly true dans le DataGridCell style et pour gérer l'événement keydown initial

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

et le code suivant derrière pour arrêter l'édition initiale

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;
    }
}

Espérons que cela est utile.

Dans mon cas, j'utilisais DataGridTextColumn. Je mets la propriété IsEnabled ContentPresenter dans le style comme suit, et il fonctionne très 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>

Vous pouvez le faire avec un modèle de données plus simple.

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

...

<DataGridTemplateColumn CellTemplate="{StaticResource MyTemplate}" />
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top