Domanda

ho capito si può rendere l'intero DataGrid o una colonna intera readyonly (IsReadOnly = true). Tuttavia, a livello cellulare questa proprietà è solo pronto. Ma ho bisogno di questo livello di granularità. C'è blog su aggiungendo IsReadOnly a una riga modificando il codice sorgente in vecchi tempi, quando DataGrid era di dominio pubblico, ma ora non ho il codice sorgente per il DataGrid. Cosa c'è soluzione?

Fare cella disabilitata (IsEnabled = false) quasi incontra il mio bisogno. Ma il problema è che non si può nemmeno fare clic sulla cella disabilitata per selezionare la riga (non ho modo di selezione fila completa).

EDIT: Dal momento che nessuno ha risposto a questa domanda, quindi credo che non è una soluzione semplice. Ecco una possibile soluzione: rendere la cella non modificabile. L'unico problema è che clic sulla cella non selezionare la riga. Ho appena notato che MouseDown o MouseUp caso di DataGrid è ancora licenziato quando si fa clic sulla cella disabilitato. In questo gestore di eventi, se ho potuto capire la fila è scattato, ho potuto selezionare la riga di codice. Tuttavia, non riuscivo a capire come trovare la riga sottostante dal DataGrid.InputHitTest. Può qualcuno si prega di darmi qualche suggerimento?

È stato utile?

Soluzione

che ho incontrato lo stesso problema, la cella deve essere di sola lettura in alcune righe, ma non negli altri. Ecco una soluzione soluzione:

L'idea è quella di cambiare dinamicamente la CellEditingTemplate tra due modelli, uno è la stessa di quella nella CellTemplate, l'altra è per la modifica. Questo rende la modalità di modifica comporta esattamente uguale a quella della cella non modifica anche se è in modalità di modifica.

Il seguente è alcuni esempi di codice per fare questo, si noti che questo approccio richiede DataGridTemplateColumn:

In primo luogo, definire due modelli per sola lettura e la modifica di celle:

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

Quindi definire un modello di dati con lo strato ContentPresenter supplementare e uso Trigger per commutare il ContentTemplate del ContentPresenter, quindi questi due modelli possono essere commutati dinamicamente dal IsEditable binding:

<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

Altri suggerimenti

Dopo molte ricerche e la sperimentazione utilizzando IsTabStop = False e Focusable = False funziona meglio per me.

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

C'è una proprietà su DataGridCell.IsReadOnly che si potrebbe pensare è possibile associare a,
per esempio. utilizzando XAML in questo modo:

<!-- 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 questo non funzionerà, perché questa proprietà non è scrivibile.
Poi si potrebbe tentare di eventi intercetta e del mouse di arresto, ma questo non impedisce all'utente di entrare in modalità di modifica con il tasto F2.

Il modo in cui questo è stato sloved ascoltando per la PreviewExecutedEvent sul DataGrid e quindi condizionalmente segnalando come gestito.
Per esempio. con l'aggiunta di codice simile a questo per il costruttore della mia finestra o UserControl (o in altro luogo più adatto):

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

Facendo in questo modo le cellule sono ancora attivabile e selezionabile.
Ma l'utente non sarà in grado di entrare in modalità di modifica a meno che i vostri elementi del modello consentono per la riga data.
E non soffrirete i costi delle prestazioni o complessità utilizzando il DataGridTemplateColumn.

Ho risolto questo problema nella mia applicazione impostando l'oggetto sottostante nella cella (ad es CheckBox.) - IsHitTestVisible = false; Focusable = false;

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

"riga" è una DataGridRow. IsHitTestVisible = false, significa che non puoi clic / selezionate / manipolare l'oggetto sottostante tramite il mouse, ma è ancora possibile selezionare il DataGridCell. mezzi Focusable = false, che non è possibile selezionare / manipolare l'oggetto sottostante con la tastiera. Questo dà l'illusione di una cella ReadOnly, ma è ancora possibile selezionare la cella e sono sicuro che se il DataGrid è impostato per SelectionMode = FullRow quindi facendo clic sul "sola lettura" delle cellule selezionerà l'intero fila.

La mia soluzione è quella di utilizzare il legame al DataGridTemplateColumn con convertitore.

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

ed il convertitore:

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

In base a commento @sohum, qui è possibile utilizzare la versione semplificata della risposta contrassegnato come risposta.

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

È possibile utilizzare in un secondo momento come un rapporto Comportamento Proprietà.

Un modo di ottenere selezionabile, celle di testo di sola lettura per il DataGrid è quello di utilizzare template e stile in questo modo:

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

E per CS backend:

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

Questo è un po 'tardi, ma, stavo cercando in questo pure, queste soluzioni funzionano bene, ma ho bisogno di qualcosa di un po' diverso, ho fatto la seguente e funziona esattamente come volevo e quello che la domanda sta cercando.

I essenzialmente volevo essere in grado di entrare in modalità di modifica per il cellulare e hanno tutto ciò che gli altri modelli e logica di comando lo stesso, pur non essendo in grado di modificare la cella.

La soluzione per tutto questo è quello di impostare la proprietà TextBox.IsReadOnly su true nel Style DataGridCell e per gestire l'evento keydown iniziale

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

e il seguente codice dietro per fermare la modifica iniziale

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

Speriamo che questo sia utile.

Nel mio caso ho usato DataGridTextColumn. Ho impostato la proprietà IsEnabled su ContentPresenter in stile come segue e funziona bene -

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

Si può fare questo con un modello di dati più semplice.

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

...

<DataGridTemplateColumn CellTemplate="{StaticResource MyTemplate}" />
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top