【问题标题】:WPF DataGridTemplateColumn MVVM DataContext Property Accessibility IssueWPF DataGridTemplateColumn MVVM DataContext 属性可访问性问题
【发布时间】:2018-03-14 00:10:39
【问题描述】:

我正在尝试访问每行内的布尔属性值,以便可以使用它来设置按钮可见性,但是我无法使用 DataGridTemplateColumn 访问它。我能够将整个行对象放入传递给按钮命令的参数中,但是我不能只获取 UseSetting 值来传递给 Visibility 转换器。我尝试了如下所示的背负文本列,但是转换器似乎仅在第一次加载视图时触发。使用断点我可以看到对 UseSetting 属性的后续更改不会触发转换器。我确实在 DataGrid 中使用的自定义类上正确设置了 NotifyOfPropertyChange。

在使用 DataGridTemplateColumn 时,访问行属性的最佳方法是什么?我在 DataGridTemplateColumn 中创建自己的复选框而不是使用 CheckboxColumn 的原因是因为 CheckboxColumn 需要先选中行,然后才能选中它,并且我需要单击复选框来选中它。

需要明确的是,这个视图没有代码。一切都在视图模型中,例如数据网格的项目源,它是我在下面包含的自定义类“SharedSetting”的 ObservableCollection。

<DataGrid MaxHeight="400" VerticalScrollBarVisibility="Auto" BorderThickness="1" CanUserAddRows="False" CanUserDeleteRows="False" BorderBrush="{DynamicResource AccentBaseColorBrush}" GridLinesVisibility="Horizontal"  AutoGenerateColumns="False"  ItemsSource="{Binding SharedSettings, NotifyOnSourceUpdated=True}">
<DataGrid.ColumnHeaderStyle>
    <Style TargetType="{x:Type DataGridColumnHeader}" >
        <Setter Property="FontWeight"  Value="Bold" />
        <Setter Property="HorizontalAlignment" Value="Stretch" />
        <Setter Property="HorizontalContentAlignment" Value="Center" />
        <Setter Property="FontSize" Value="10" />
    </Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
    <DataGridTextColumn Width="250" Header="Setting" Binding="{Binding Setting}" />
    <DataGridTextColumn Width="300" Header="Value" ElementStyle="{StaticResource WrapText}" Binding="{Binding Value}" />
    <DataGridTextColumn Width="75" Header="Use Setting" Binding="{Binding UseSetting, Mode=TwoWay}" x:Name="stackRowUseSetting" />
    <DataGridTemplateColumn Width="50" >
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <Grid Width="30" Height="30" x:Name="stackRow2">
                    <Button Background="Transparent" Foreground="{StaticResource AccentColorBrush}" ToolTip="Do Not Use Setting"  Visibility="{Binding ElementName=stackRowUseSetting, Path=Binding, Converter={StaticResource TrueToVisibleConverter}}"  BorderThickness="0" Margin="0,0,0,0" DataContext="{Binding ElementName=MainGrid, Path=DataContext}" Command="{Binding ToggleUseSettingCommand}" CommandParameter="{Binding ElementName=stackRow2,Path=DataContext}">
                        <iconPacks:PackIconMaterial Kind="CheckCircleOutline" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0"    />
                    </Button>
                    <Button Background="Transparent" Foreground="{StaticResource AccentColorBrush}" ToolTip="Use Setting" Visibility="{Binding ElementName=stackRowUseSetting, Path=Binding, Converter={StaticResource FalseToVisibleConverter}}" BorderThickness="0" Margin="0,0,0,0" DataContext="{Binding ElementName=MainGrid, Path=DataContext}" Command="{Binding ToggleUseSettingCommand}" CommandParameter="{Binding ElementName=stackRow2,Path=DataContext}">
                        <iconPacks:PackIconMaterial Kind="CheckboxBlankCircleOutline" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0"    />
                    </Button>

                </Grid>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>


</DataGrid.Columns>
</DataGrid>

另外,上面的 XAML 正是我现在所拥有的。这里很可能有一些多余且不需要的项目。我已经添加和删除了很多东西,试图让它工作,现在有点草率。

这是带有 INotifyPropertyChanged 的​​ SharedSetting 类

public class SharedSetting : INotifyPropertyChanged
{
    private bool _useSetting;
    private object _o;
    private string _value;
    private string _setting;
    private string _group;

    public SharedSetting(string groupName, string settingName, string settingValue, object value, bool use=false)
    {
        Group = groupName;
        Setting = settingName;
        Value = settingValue;
        Object = value;
        UseSetting = use;
    }
    public SharedSetting()
    {

    }

    public string Group
    {
        get { return _group; }
        set
        {
            _group = value;
            NotifyPropertyChanged();
        }
    }

    public string Setting
    {
        get { return _setting; }
        set
        {
            _setting = value;
            NotifyPropertyChanged();
        }
    }

    public string Value
    {
        get { return _value; }
        set
        {
            _value = value;
            NotifyPropertyChanged();
        }
    }

    public object Object
    {
        get { return _o; }
        set
        {
            _o = value;
            NotifyPropertyChanged();
        }
    }

    public bool UseSetting
    {
        get { return _useSetting; }
        set
        {
            _useSetting = value;
            NotifyPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

这是转换器之一。

public sealed class TrueToVisibleConverter : MarkupExtension, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var flag = false;
        if (value is bool)
        {
            flag = (bool) value;
        }
        var visibility = (object) (Visibility) (flag ? 0 : 2);
        return visibility;
    }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is Visibility)
        {
            var visibility = (object) ((Visibility) value == Visibility.Visible);
            return visibility;
        }
        return (object) false;
    }
}

2018 年 3 月 14 日更新

要解决下面提供的关于删除我的 DataContext 设置并像所有其他列一样使用属性的第一个答案,这是行不通的。这是我很久以前尝试的第一件事,只是为了得知 DataGridTemplateColumn 不像其他列那样继承行的数据上下文(昨天我在下面的评论中感到沮丧的原因)。我包含了一个屏幕截图,显示了智能感知错误,说明该属性不存在,当它以与它上面的列相同的方式使用时。

【问题讨论】:

  • 顺便说一句,要么我错过了一些非常简单的东西,要么设计得很糟糕。为什么 TemplateColumn 不能像其他所有列类型一样拥有相同的数据上下文?这对我来说没有任何意义,为什么它不像文本、复选框、组合等那样存在。
  • 你对这张图片提出的问题有答案吗,因为我在同一条船上。我还尝试了各种 RelativeSource 选项。令我惊讶的是,这并不像您的图像所期望的那样工作......即,一旦使用数据模板,所有数据上下文都会丢失,即使 xaml 嵌入在相同的数据网格定义中

标签: wpf mvvm datagrid datagridtemplatecolumn


【解决方案1】:

你把DataContext 改成了你的ButtonDataContext="{Binding ElementName=MainGrid, Path=DataContext}" 是错误的,所以删除它并像在 DataGridTextColumn 中那样绑定到属性。对于Command 与不在SharedSetting 中的命令的绑定,请使用ElementName(正如您为DataContext 所做的那样)或RelativeSource
更新:
应该可以,但是你也可以试试

<Button Visibility="{Binding DataContext.UseSetting, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGridRow}, Converter={StaticResource TrueToVisibleConverter}}" />

【讨论】:

  • 感谢您的意见。我用我认为你所指的截图更新了我的原始帖子。如果我弄错了,请让我知道并回复一些示例代码,这样我就可以确定我们在同一页面上。不幸的是,TemplateColumns 不像其他列那样工作。
猜你喜欢
  • 1970-01-01
  • 2011-07-17
  • 2011-06-19
  • 1970-01-01
  • 2011-08-10
  • 1970-01-01
  • 2011-03-24
  • 1970-01-01
  • 2011-05-12
相关资源
最近更新 更多