【发布时间】:2015-05-02 07:06:56
【问题描述】:
请注意,这个问题是 Silverlight 5 特有的。有很多类似的问题,但通常是关于 WPF 或以前的 Silverlight 版本。其他目标是 Silverlight 5,但与
DataGrid以外的控件有关。我一直找不到与这个问题完全相同的现有问题;至少没有一个适合我的答案。
假设我有这个非常简单的DataGrid(XAML 和 C# 代码进一步向下),它绑定到具有两个属性 Selected 和 Text 的 INotifyPropertyChanged 类型的集合:
我想将每一行的背景颜色绑定到其数据项的Selected 属性(使用一些bool-to-Brush 转换器)。通常的行状态(正常、选中、鼠标悬停等)的视觉效果和过渡不应受到影响;也就是说,普通行会被着色,交替行会更亮一些,鼠标悬停的行会更暗,选定的行会比这更暗,等等。
在其他地方看到的一些明显的解决方案:
我已经搜索了几个小时的解决方案,并且有很多类似的问题在四处游荡,但似乎没有一个答案适用于 Silverlight 5,或者它们不起作用。似乎有几种方法:
-
覆盖
DataGridRow控件模板并绑定其BackgroundRectangle的Background属性:<sdk:DataGrid …> <sdk:DataGrid.RowStyle> <Style TargetType="sdk:DataGridRow"> <Setter Property="Template"> <Setter.Value> <ControlTemplate> … <Rectangle x:Name="BackgroundRectangle" … Background="{Binding Selected, Converter={StaticResource boolToBrush}}" /> … </ControlTemplate> </Setter.Value> </Setter> </Style> </sdk:DataGrid.RowStyle> … </sdk:DataGrid>这最初有效,并且视觉状态被正确渲染(因为
DataGrid视觉状态仅影响BackgroundRectangle的不透明度;有关详细信息,请参阅the default control template definition)。这样做的问题是当绑定项目的
Selected属性值改变时行背景颜色不会改变。就好像{Binding}有一个Mode=OneTime。另外,我读到应该避免控制模板中的数据绑定。
TemplateBindings 在控制模板中很好,但普通的Bindings 可能不属于这里。 -
将所有列更改为
<sdk:DataGridTemplateColumn>并使用数据模板:<sdk:DataGrid …> <sdk:DataGrid.Columns> <sdk:DataGridTemplateColumn Header="Selected"> <sdk:DataGridTemplateColumn.CellTemplate> <DataTemplate> <Grid Background="{Binding Selected, Converter={StaticResource boolToBrush}}"> <CheckBox IsChecked="{Binding Selected}" /> </Grid> </DataTemplate> </sdk:DataGridTemplateColumn.CellTemplate> … <!-- repeat the above for each column --> </sdk:DataGridTemplateColumn> </sdk:DataGrid.Columns> … </sdk:DataGrid>这更糟。单元格获得正确的背景颜色,但数据网格的各种视觉状态不再正确应用。此外,每列都必须转换为模板列。第三,当绑定的属性值改变时,背景颜色不会更新。
使用 Expression Blend 数据触发器(来自
System.Windows.Interactivity和Microsoft.Expression.Interactivity.Core命名空间的类型)。老实说,我根本无法弄清楚这应该如何工作。
问题:
我真的不想在手动执行此操作的地方诉诸命令式代码隐藏。但是我怎样才能在 XAML 中做我想做的事情,以一种适当的方式来尊重 DataGridRow 视觉状态和行为,并在绑定属性更改时更新行背景?
谁能给我一个 XAML 示例,如何以这种方式将每一行的背景颜色绑定到其绑定项的属性之一?
上述数据网格的 XAML 和 C# 代码:
<UserControl x:Class="SomeApplication.MainView"
…
xmlns:local="clr-namespace:SomeApplication"
xmlns:sdk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data">
<!-- sample data context -->
<UserControl.DataContext>
<local:MainViewModel>
<local:MainViewModel.Things>
<local:ThingViewModel Text="A" />
<local:ThingViewModel Text="B" />
<local:ThingViewModel Text="C" />
<local:ThingViewModel Text="D" Selected="True" />
<local:ThingViewModel Text="E" />
</local:MainViewModel.Things>
</local:MainViewModel>
</UserControl.DataContext>
<Grid>
<sdk:DataGrid ItemsSource="{Binding Things}" AutoGenerateColumns="False">
<sdk:DataGrid.Columns>
<sdk:DataGridCheckBoxColumn Header="Selected" Binding="{Binding Selected}" />
<sdk:DataGridTextColumn Header="Text" Binding="{Binding Text}" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
</UserControl>
namespace SomeApplication
{
public interface IMainViewModel
{
ObservableCollection<ThingViewModel> Things { get; }
}
public interface IThingViewModel : INotifyPropertyChanged
{
bool Selected { get; set; }
string Text { get; set; }
}
// straightforward implementations, omitted for brevity's sake:
public partial class MainViewModel : IMainViewModel { }
public partial class ThingViewModel : IThingViewModel { }
}
【问题讨论】:
标签: datagrid datatemplate silverlight-5.0 controltemplate datatrigger