سؤال

أنا أفهم أنه يمكنك جعل بيانات البيانات بأكملها أو عمودًا كاملًا جاهزًا (isReadonly = true). ومع ذلك ، على مستوى الخلية هذه الخاصية جاهزة فقط. لكني بحاجة إلى هذا المستوى من التفاصيل. هناك مدونة حول إضافة isReadonly إلى صف عن طريق تغيير الكود المصدر في الأيام الخوالي عندما كان DataGrid مجالًا عامًا ، لكن الآن ليس لدي رمز مصدر لـ DataGrid. ما هو الحل؟

جعل الخلية معطلة (isenabled = خطأ) تلبي تقريبا حاجتي. ولكن المشكلة هي أنه لا يمكنك حتى النقر فوق الخلية المعوقة لتحديد الصف (لدي وضع اختيار الصف الكامل).

تحرير: بما أن أحداً لم يرد على هذا السؤال ، لذلك أعتقد أنه ليس حلًا سهلاً. فيما يلي حل محتمل: اجعل الخلية غير قابلة للتهاب. المشكلة الوحيدة هي أن النقر على الخلية لا يحدد الصف. لقد لاحظت للتو أنه لا يزال يتم إطلاق حدث Mousedown أو Mouseup من DataGrid عند النقر على الخلية المعوقة. في معالج الحدث هذا ، إذا كان بإمكاني معرفة الصف الذي نقره ، فيمكنني تحديد الصف برمجيًا. ومع ذلك ، لم أستطع معرفة كيفية العثور على الصف الأساسي من DataGrid.InputHitTest. هل يمكن لأحد أن يعطيني بعض النصيحة؟

هل كانت مفيدة؟

المحلول

لقد واجهت نفس المشكلة ، يجب أن تكون الخلية قراءة فقط في بعض الصفوف ولكن ليس في الآخرين. هنا حل حلول:

الفكرة هي تبديل ديناميكي CellEditingTemplate بين قاللين ، واحد هو نفسه في CellTemplate, والآخر هو التحرير. هذا يجعل وضع التحرير يتصرف تمامًا مثل خلية عدم التحرير على الرغم من أنه في وضع التحرير.

فيما يلي بعض رمز العينة للقيام بذلك ، لاحظ أن هذا النهج يتطلب DataGridTemplateColumn:

أولاً ، حدد قالبين لخلايا القراءة فقط والتحرير:

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

ثم حدد قالب بيانات مع إضافي ContentPresenter طبقة واستخدام Trigger لتبديل ContentTemplate التابع ContentPresenter, ، لذلك يمكن تبديل القوالب المذكورة أعلاه ديناميكيا بواسطة IsEditable ربط:

<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

نصائح أخرى

بعد الكثير من البحث والتجريب باستخدام iStabstop = false و focusable = false يعمل بشكل أفضل بالنسبة لي.

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

هناك خاصية على DataGridCell.IsReadOnly قد تعتقد أنه يمكنك ربط ،
على سبيل المثال باستخدام XAML مثل هذا:

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

للأسف لن ينجح هذا لأن هذه الخاصية غير قابلة للكتابة.
بعد ذلك ، قد تحاول اعتراض ووقف أحداث الماوس ، ولكن هذا لن يمنع المستخدم من إدخال وضع التحرير باستخدام مفتاح F2.

كانت الطريقة التي قطعت بها هذا من خلال الاستماع إلى PreviewExecutedEvent على DataGrid ثم وضع علامة مشروط على أنها معالجة.
على سبيل المثال ، بإضافة رمز مشابه لهذا إلى مُنشئ النافذة أو UserControl (أو مكان آخر أكثر ملاءمة):

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

من خلال القيام بذلك مثل هذا ، لا تزال الخلايا قابلة للتركيز ويمكن اختيارها.
لكن المستخدم لن يتمكن من إدخال وضع التحرير ما لم تسمح ذلك عناصر النموذج الخاصة بك بالصف المحدد.
ولن تعاني من تكاليف الأداء أو التعقيدات باستخدام DataGridTemplateColumn.

لقد قمت بحل هذه المشكلة في طلبي عن طريق تعيين الكائن الأساسي في الخلية (مثل مربع الاختيار) - Ishittestvisible = false ؛ Focusable = false ؛

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

"ROW" هو DataGridRow. Ishittestvisible = false ، يعني أنه لا يمكنك النقر/تحديد/معالجة الكائن الأساسي عبر الماوس ، ولكن لا يزال بإمكانك تحديد DataGridCell. Focusable = false ، يعني أنه لا يمكنك تحديد/معالجة الكائن الأساسي باستخدام لوحة المفاتيح. هذا يعطي وهم خلية قراء SelectionMode = FullRow ثم النقر فوق الخلية "اقرأ فقط" سيقوم بتحديد الصف بأكمله.

الحل الخاص بي هو استخدام الربط مع DataGridTemplateColumn مع المحول.

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

والمحول:

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

استنادًا إلى تعليق sohum ، يمكنك هنا استخدام نسخة مبسطة من الاستجابة التي تم وضع علامة عليها كإجابة.

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

يمكنك استخدامه لاحقًا كسلوك الخاصية المرفقة.

تتمثل إحدى طرق الحصول على خلايا نصية قابلة للاختيار وقراءة فقط لـ DataGrid في استخدام القالب والأناقة مثل هذا:

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

وخلفية CS:

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

هذا متأخر بعض الشيء ، لكنني كنت أبحث في هذا أيضًا ، تعمل هذه الحلول بشكل جيد ، لكنني كنت بحاجة إلى شيء مختلف قليلاً ، لقد فعلت ما يلي ويعمل تمامًا كما أردت وما يبحث عنه السؤال.

لقد أردت بشكل أساسي أن أكون قادرًا على إدخال وضع التحرير للخلية ولدي كل تلك القوالب الأخرى ومنطق القيادة كما هو مع عدم القدرة على تحرير الخلية.

الحل لكل هذا هو تعيين خاصية textbox.isreadonly

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

والرمز التالي وراء إيقاف التحرير الأولي

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

نأمل أن يكون هذا مفيدًا.

في حالتي كنت أستخدم DataGridTextColumn. قمت بتعيين الخاصية ISENABDER على ContentPresenter في الأناقة على النحو التالي ، وهي تعمل بشكل جيد -

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

يمكنك القيام بذلك باستخدام قالب بيانات أبسط.

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

...

<DataGridTemplateColumn CellTemplate="{StaticResource MyTemplate}" />
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top