简体   繁体   English

将DataGridTextColumn的IsReadOnly绑定到DataGridTemplateColumn复选框IsChecked

[英]Binding IsReadOnly of a DataGridTextColumn to a DataGridTemplateColumn checkbox IsChecked

Basically, I have a DataGrid with several columns, and I want to enable (changing the IsReadOnly property) a DataGridTextColumn based on a CheckBox IsChecked , located in another DataGridTemplateColumn of the same DataGrid . 基本上,我有一个DataGrid几个栏目,我想启用(改变IsReadOnly属性)一个DataGridTextColumn基于一个CheckBox IsChecked ,位于另一个DataGridTemplateColumn相同的DataGrid

Here is (the important part of) the code: 这是代码的(重要部分):

<DataGrid Name="lstTags" Grid.Row="0" ItemsSource="{Binding Path = LinesCollection}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" SelectionMode="Single" LostFocus="lstTags_LostFocus" SelectionChanged="lstTags_SelectionChanged">
    <DataGrid.Columns>
        <DataGridTemplateColumn x:Name="colAutoScale" Header="Auto Scale">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox x:Name="ckbAutoScale" HorizontalAlignment="Center" IsChecked="{Binding AutoScale, UpdateSourceTrigger=PropertyChanged}"/>
                 </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTextColumn Header="Scale" Binding="{Binding Path=Scale}" IsReadOnly="{Binding ElementName ckbAutoScale, Path=IsChecked}" Width="60" />
    </DataGrid.Columns>
</DataGrid>

It is worth mentioning that I also want to invert the value of the IsChecked property, that is 值得一提的是,我还想反转IsChecked属性的值,即

  • IsChecked = true => IsReadOnly = false ; IsChecked = true => IsReadOnly = false ;
  • IsChecked = false => IsReadOnly = true . IsChecked = false => IsReadOnly = true

I would probably achieve this with a simple Converter , but I need that first part working tho. 我可能会用一个简单的Converter实现此目的,但是我需要第一部分工作。

EDIT: 编辑:

Answering a good question, my goal is to disable the adjacent cell (same row), not the whole column. 回答一个好问题,我的目标是禁用相邻的单元格 (同一行),而不是整个列。

This type of problem is really the reason the Model-View-ViewModel (MVVM) pattern exists. 这类问题确实是Model-View-ViewModel(MVVM)模式存在的原因。

With MVVM, you bind to view models that have the exact properties needed to support the view. 使用MVVM,您可以绑定到具有支持视图所需的确切属性的视图模型。 This allows the model to be more concerned with what data needs to be persisted. 这使模型可以更加关注需要保留哪些数据。

So, for your problem, you would need to create a LineViewModel , which would look something like this: 因此,对于您的问题,您需要创建一个LineViewModel ,看起来像这样:

public class LineViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private bool _isAutoScale;
    private double _scale;

    public bool IsAutoScale
    {
        get { return _isAutoScale; }
        set
        {
            if (value == _isAutoScale) return;
            _isAutoScale = value;
            OnPropertyChange("IsAutoScale");
            OnPropertyChange("IsReadOnly");
        }
    }

    public double Scale
    {
        get { return _scale; }
        set
        {
            if (value == _scale) return;
            _scale = value;
            OnPropertyChange("Scale");
        }
    }

    public bool IsReadOnly => !IsAutoScale;

    private void OnPropertyChange(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Meanwhile, you would also want to create a parent view model called MainWindowViewModel (or something that makes sense for your situation). 同时,您还想创建一个称为MainWindowViewModel的父视图模型(或对您的情况有意义的东西)。 Here is a very crude version: 这是一个非常原始的版本:

public class MainWindowViewModel : INotifyPropertyChanged
{
    private List<LineViewModel> _lineViewModels;
    public event PropertyChangedEventHandler PropertyChanged;

    public List<LineViewModel> LineViewModels
    {
        get { return _lineViewModels; }
        set
        {
            if (value == _lineViewModels) return;
            _lineViewModels = value;
            OnPropertyChange("LineViewModels");
        }
    }

    public MainWindowViewModel()
    {
        LineViewModels = new[]
        {
            new { AutoScale = false, Scale = 0.2 },
            new { AutoScale = true, Scale = 0.3 },
            new { AutoScale = false, Scale = 0.4 },
        }
            .Select(
                x => new LineViewModel
                {
                    IsAutoScale = x.AutoScale,
                    Scale = x.Scale
                })
            .ToList();
    }

    private void OnPropertyChange(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Finally, you would update your XAML file to look something like this: 最后,您将更新XAML文件,使其看起来像这样:

<Window x:Class="Sandbox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:sandbox="clr-namespace:Sandbox"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="350"
        Width="525">
    <Window.DataContext>
        <sandbox:MainWindowViewModel />
    </Window.DataContext>
    <DataGrid ItemsSource="{Binding LineViewModels}"
              HorizontalAlignment="Stretch"
              VerticalAlignment="Stretch"
              AutoGenerateColumns="False"
              CanUserAddRows="False"
              CanUserDeleteRows="False"
              SelectionMode="Single">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Auto Scale">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <CheckBox HorizontalAlignment="Center"
                                  IsChecked="{Binding IsAutoScale}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="Auto Scale">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBox Text="{Binding Scale}"
                                 IsReadOnly="{Binding IsReadOnly}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Window>

So, basically, the view logic for MainWindow is determined by MainWindowViewModel and the view logic for each row of the DataGrid is controlled by a LineViewModel . 因此,基本上,对于视图逻辑MainWindow由下式确定MainWindowViewModel并为各行的视图逻辑DataGrid由受控LineViewModel

Note that a lot of the boilerplate for implementing INotifyPropertyChanged can be simplified using libraries/NuGet packages like MVVM Light Toolkit and PropertyChanged.Fody. 请注意,可以使用诸如MVVM Light Toolkit和PropertyChanged.Fody之类的库/ NuGet包来简化实现INotifyPropertyChanged的许多样板。

Use below binding for your Scale Column : 将以下绑定用于“ Scale Column

 <DataGridTextColumn Header="Scale" Binding="{Binding Path=Scale}" Width="60" >
      <DataGridTextColumn.CellStyle>
           <Style TargetType="DataGridCell">
                <Setter Property="IsEnabled" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridCellsPanel}},Path=Children[0].Content.Content.AutoScale}" />
           </Style>
      </DataGridTextColumn.CellStyle>
</DataGridTextColumn>

OR simply 或者简单地

<DataGridTextColumn Header="Scale" Binding="{Binding Path=Scale}" Width="60" >
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="IsEnabled" Value="{Binding Path=AutoScale}" />
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>

Output: 输出:

只读

PS: Above Solution 1 is specific to your code, cause Auto Scale column is at 0 Index that's why I used Children[0] in Binding . PS:以上解决方案1特定于您的代码,因为“ Auto Scale column位于0 Index ,这就是为什么我在Binding使用Children[0]的原因。 Please change if there is any contextual need. 如果有任何上下文需要,请更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM