【问题标题】:In Silverlight 5, how do I bind each DataGrid's row background color to one of its bound item's properties?在 Silverlight 5 中,如何将每个 DataGrid 的行背景颜色绑定到其绑定项的属性之一?
【发布时间】:2015-05-02 07:06:56
【问题描述】:

请注意,这个问题是 Silverlight 5 特有的。有很多类似的问题,但通常是关于 WPF 或以前的 Silverlight 版本。其他目标是 Silverlight 5,但与 DataGrid 以外的控件有关。我一直找不到与这个问题完全相同的现有问题;至少没有一个适合我的答案。

假设我有这个非常简单的DataGrid(XAML 和 C# 代码进一步向下),它绑定到具有两个属性 SelectedTextINotifyPropertyChanged 类型的集合:

我想将每一行的背景颜色绑定到其数据项的Selected 属性(使用一些bool-to-Brush 转换器)。通常的行状态(正常、选中、鼠标悬停等)的视觉效果和过渡不应受到影响;也就是说,普通行会被着色,交替行会更亮一些,鼠标悬停的行会更暗,选定的行会比这更暗,等等。

在其他地方看到的一些明显的解决方案:

我已经搜索了几个小时的解决方案,并且有很多类似的问题在四处游荡,但似乎没有一个答案适用于 Silverlight 5,或者它们不起作用。似乎有几种方法:

  1. 覆盖DataGridRow控件模板并绑定其BackgroundRectangleBackground属性:

    <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 可能不属于这里。

  2. 将所有列更改为&lt;sdk:DataGridTemplateColumn&gt;并使用数据模板:

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

    这更糟。单元格获得正确的背景颜色,但数据网格的各种视觉状态不再正确应用。此外,每列都必须转换为模板列。第三,当绑定的属性值改变时,背景颜色不会更新。

  3. 使用 Expression Blend 数据触发器(来自 System.Windows.InteractivityMicrosoft.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


    【解决方案1】:

    似乎可行的一件事是将覆盖控制模板和将 Expression Blend 数据触发器放在 BackgroundRectangle 中的组合。

    DataGridRow 的默认控制模板开始(您可以找到on the MSDN page 'DataGrid Styles and Templates')。唯一需要改变的是&lt;Rectangle x:Name="BackgroundRectangle"&gt;

    <!-- 
      xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
      xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expressions.Interactions" 
    -->
    
    <sdk:DataGrid …>
      <sdk:DataGrid.RowStyle>
        <Style TargetType="sdk:DataGridRow">
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate>
                … <!-- use DataGridRow standard control template, except for this: -->
                <Rectangle x:Name="BackgroundRectangle" …
                           Background="{Binding Selected, Converter={StaticResource boolToBrush}}">
                  <i:Interaction.DataTriggers>
                    <ei:PropertyChangedTrigger Binding="{Binding Selected}" Value="True">
                      <ei:PropertyChangedTrigger.Actions>
                        <ei:ChangePropertyAction TargetName="BackgroundRectangle"
                                                 PropertyName="Fill" 
                                                 Value="{Binding Selected, Converter={StaticResource boolToBrush}}" />
                      </ei:PropertyChangedTrigger.Actions>
                    </ei:PropertyChangedTrigger>
                  </i:Interaction.DataTriggers>
                <Rectangle>
                …
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
      </sdk:DataGrid.RowStyle>
      …
    </sdk:DataGrid>
    

    由于一行的背景矩形在控件模板内,而且背景应该随着数据而变化,看来在控件模板内放置数据绑定实际上是不可避免的。

    【讨论】:

      猜你喜欢
      • 2011-05-15
      • 1970-01-01
      • 2015-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多