简体   繁体   English

使用 CheckBox MVVM 更改 WPF DataGrid 行背景颜色

[英]Change WPF DataGrid rows background color using CheckBox MVVM

I have converter for applying background color for DataGrid rows based on values in one column.我有转换器,用于根据一列中的值为 DataGrid 行应用背景颜色。 It is working fine and is applying background color "on load".它工作正常并且正在“加载”应用背景颜色。 However I decided to dive deeper into WPF and MVVM and try to attach this event to CheckBox, but failed at this point.但是我决定更深入地研究 WPF 和 MVVM 并尝试将此事件附加到 CheckBox,但此时失败了。 I am not getting any errors but my CheckBox does not work either.我没有收到任何错误,但我的 CheckBox 也不起作用。 Any suggestions what should be edited?任何建议应该编辑什么? I guess I need to attach Convert event somehow to BacgroundColorBool ?我想我需要以某种方式将Convert事件附加到BacgroundColorBool

IDToBackgroundConverter.cs: IDToBackgroundConverter.cs:

using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;

namespace Inspector_FilterTest
{
    class IDToBackgroundConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is string)
            {
                if (value.ToString().Trim().StartsWith("7")) return Brushes.DarkSlateBlue;
                if (value.ToString().Trim().StartsWith("6")) return Brushes.Peru;
            }
            // value is not an integer. Do not throw an exception
            // in the converter, but return something that is obviously wrong
            return Brushes.Firebrick;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

    }
}

I use it in XAML:我在 XAML 中使用它:

<Window.Resources>

        <Inspector_FilterTest:IDToBackgroundConverter x:Key="IDToBackgroundConverter"/>

</Window.Resources>

...

        <DataGrid x:Name="DataGrid1" ItemsSource="{Binding MainDataTable}">
            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow" >
                    <Setter Property="Background" Value="{Binding YRNRO, Converter={StaticResource IDToBackgroundConverter}}" />
                </Style>
            </DataGrid.RowStyle>
         </DataGrid>

This is working fine and background colors are set (based on starting number in YRNRO) when I am loading my DataGrid.当我加载我的 DataGrid 时,这工作正常并且背景颜色设置(基于 YRNRO 中的起始编号)。 However I would like to be able to control this with CheckBox.但是我希望能够使用 CheckBox 来控制它。

I have created a CheckBox:我创建了一个复选框:

ViewModel_Main.cs: ViewModel_Main.cs:

    // Binding checkbox background color
    private bool _BacgroundColorBool;
    public bool BacgroundColorBool
    {
        get => this._BacgroundColorBool;
        set
        {
            this._BacgroundColorBool = value;
            OnPropertyChanged();

            // Refresh the DataTable filter expression
            EnableRowFiltering();
        }
    }

XAML: XAML:

    <CheckBox Style="{StaticResource MyCheckBox}" IsChecked="{Binding BacgroundColorBool}" x:Name="ActiveCustomer_Copy" Content="" HorizontalAlignment="Left" Margin="221,55,0,0" VerticalAlignment="Top"/>

but I don't understand how to connect this all together in order to be able to control "background fill applied"/"background fill not applied" with CheckBox.但我不明白如何将这些连接在一起,以便能够使用 CheckBox 控制“应用背景填充”/“未应用背景填充”。


EDIT:编辑:

Some corrections done to code originally provided by BionicCode (no errors in debugger anymore, I hope this is correct?).对 BionicCode 最初提供的代码进行了一些更正(调试器中不再有错误,我希望这是正确的?)。 In order to get color back to transparent in Datagrid after CheckBox is unchecked pay attention to return Brushes.Transparent;为了在未选中 CheckBox 后使 Datagrid 中的颜色恢复透明,请注意return Brushes.Transparent; . . That is where you can apply "revertBack" logic.这就是您可以应用“revertBack”逻辑的地方。

using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;

namespace Liinos_inspector_FilterTest
{
    class IDToBackgroundConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            // The order of the parameters in the 'values' array is equal to the order 
            // of the input binding as they are defined in the MultiBinding

            var isBackgroundEnabled = (bool)values[0];
            if (!isBackgroundEnabled)
            {
                return Brushes.Transparent;
            }

            if (values[1] is string stringValue)
            {
                return stringValue.Trim().StartsWith("7") 
                ? Brushes.DarkSlateBlue
                : stringValue.Trim().StartsWith("6") 
                  ? Brushes.Peru
                  : Brushes.Firebrick;
            }

            return Binding.DoNothing;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

One solution, that doesn't require modification of your view model, is to use a MultiBinding with a IMultiValueConverter .一种不需要修改视图模型的解决方案是将MultiBindingIMultiValueConverter一起使用。 A IMultiValueConverter accepts multiple inputs returned from a MultiBinding , to convert them to a single output (and reverse): IMultiValueConverter接受从MultiBinding返回的多个输入,将它们转换为单个输出(和反向):

First, turn the IValueConverter into a IMultiValueConverter .首先,将IValueConverter转换为IMultiValueConverter
It's best practice to throw the exception that describes the cause of the error the best.最好的做法是抛出最能描述错误原因的异常。
The NotImplementedException is primarily intended to notify the developer that he forgot to implement a relevant and referenced method. NotImplementedException主要用于通知开发人员他忘记实现相关和引用的方法。 It's like a 'TODO'.这就像一个“待办事项”。 Since you deliberately decided not to implement the ConvertBack member, because you decided not to support the backwards conversion, you should throw a NotSupportedException instead.由于您故意决定不实现ConvertBack成员,因为您决定不支持向后转换,因此您应该抛出NotSupportedException This notifies the consumer of your type that the method is not supported instead of implying that the author simply forgot to implement it.这会通知您的类型的使用者该方法不受支持,而不是暗示作者只是忘记实现它。

class IDToBackgroundConverter : IMultiValueConverter
{      
  public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  { 
    // The order of the parameters in the 'values' array is equal to the order 
    // of the input binding as they are defined in the MultiBinding

    var isBackgroundEnabled = (bool) values[0];
    if (!isBackgroundEnabled)
    {
      return Brushes.Transparent;
    }
    
    if (values[1] is string stringValue)
    {
      return stringValue.Trim().StartsWith("7") 
        ? Brushes.DarkSlateBlue 
        : stringValue.Trim().StartsWith("6") 
          ? Brushes.Peru
          : Brushes.Firebrick;
    }

    return Binding.DoNothing;
  }

  // Throw a NotSupportedException instead of a NotImplementedException
  public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) 
    => throw new NotSupportedException();
}

Setup the MultiBinding :设置MultiBinding

<CheckBox IsChecked="{Binding BackgroundColorBool}" />

<DataGrid>
  <DataGrid.RowStyle>
    <Style TargetType="DataGridRow">
      <Setter Property="Background">
        <Setter.Value>
          <MultiBinding>
            <MultiBinding.Converter>
              <IDToBackgroundConverter />
            </MultiBinding.Converter>

            <Binding Path="BackgroundColorBool" />
            <Binding Path="YRNRO" />
          </MultiBinding>
        </Setter.Value>
      </Setter>
    </Style>
  </DataGrid.RowStyle>
</DataGrid>

Because the purpose of the logic is to handle the coloring or visuals of the view, you should not implement this logic or store related data in the view model.因为该逻辑的目的是处理视图的着色或视觉效果,所以不应在视图模型中实现此逻辑或存储相关数据。
View and view model should never mix!视图和视图模型永远不应该混用!

Whether to use the previous example or to eliminate the BackgroundColorBool property in the view model, depends on the the purpose of the CheckBox .是使用前面的示例还是消除视图模型中的BackgroundColorBool属性,取决于CheckBox的用途。 Its name suggests a data related purpose ("ActiveCustomer...") and of course could bind to the view model.它的名字暗示了与数据相关的目的(“ActiveCustomer...”),当然可以绑定到视图模型。
But the name of the source property ("BackgroundColor..."), the CheckBox binds to, suggests a merely view related purpose.但是, CheckBox绑定到的源属性的名称(“BackgroundColor...”)表明仅与视图相关的目的。 In this case the property should not be in the view model.在这种情况下,该属性不应在视图模型中。 Instead move it as a DependencyProperty to the hosting view or bind the CheckBox directly:而是将其作为DependencyProperty移动到托管视图或直接绑定CheckBox

<CheckBox x:Name="ActiveCustomer_Copy" />

<DataGrid>
  <DataGrid.RowStyle>
    <Style TargetType="DataGridRow">
      <Setter Property="Background">
        <Setter.Value>
          <MultiBinding>
            <MultiBinding.Converter>
              <IDToBackgroundConverter />
            </MultiBinding.Converter>

            <Binding ElementName="ActiveCustomer_Copy" 
                     Path="IsChecked" />
            <Binding Path="YRNRO" />
          </MultiBinding>
        </Setter.Value>
      </Setter>
    </Style>
  </DataGrid.RowStyle>
</DataGrid>

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

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