【发布时间】: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