WPF 组合框颜色绑定问题

Posted

技术标签:

【中文标题】WPF 组合框颜色绑定问题【英文标题】:WPF Combobox Colors Binding issues 【发布时间】:2017-09-15 13:59:36 【问题描述】:

为了简单起见,我有一个颜色集合和一个绑定到它的组合框。工作,没有道具。

但是当我想用一些渐变特征来扩展颜色时,绑定不起作用,我尝试了很多东西。我真的看不出有什么大的区别。

这就是我所拥有的及其工作方式:

XAML

<ComboBox x:Name="colorCombo" Style="StaticResource myComboBoxStyle" Height="25" ItemsSource="Binding ColorCollection"      HorizontalAlignment="Left" Margin="5" Grid.Row="3" Grid.Column="4" Width="110">
<ComboBox.ItemTemplate>
    <DataTemplate>
        <Border Height="15" Width="Binding ElementName=colorCombo, Path=Width" Background="Binding Converter=StaticResource ColorToBrushConverter "/>
    </DataTemplate>
</ComboBox.ItemTemplate>

视图模型:

private Collection<Color> _colorCollection;
public Collection<Color> ColorCollection

  get  return _colorCollection; 
  set
  
    _colorCollection = value;
    this.NotifyPropertyChanged( x => x.ColorCollection );
  

集合被填充的 viewModel 的 OnLoad,所以不用担心。这又是有效的!

现在为什么这不起作用:

XAML

        <ComboBox x:Name="colorCombo2" Style="StaticResource myComboBoxStyle" Height="25" ItemsSource="Binding ColorCollection2" HorizontalAlignment="Right" Margin="5" Grid.Row="3" Grid.Column="4" Width="110">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <Border Height="15" Width="Binding ElementName=colorCombo2, Path=Width" BorderBrush="Binding BorderColor, Converter=StaticResource ColorToBrushConverter" >
                            <Border.Background >
                                <LinearGradientBrush EndPoint="0.504,1.5" StartPoint="0.504,0.03">
                                    <GradientStop Color="Binding Color1, Converter=StaticResource ColorToBrushConverter" Offset="0"/>
                                    <GradientStop Color="Binding Color2, Converter=StaticResource ColorToBrushConverter" Offset="0.567"/>
                                </LinearGradientBrush>
                            </Border.Background>
                        </Border>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>

视图模型:

private Collection<ColorGradientHelper> _colorCollection2;
public Collection<ColorGradientHelper> ColorCollection2

  get  return _colorCollection2; 
  set
  
    _colorCollection2 = value;
    this.NotifyPropertyChanged( x => x.ColorCollection2 );
  

HelperClass:

Public class ColorGradientHelper:ObservableBase 

private Color _color1;
public Color Color1

  get  return _color1; 
  set
  
    _color1 = value;
    this.NotifyPropertyChanged( x => x.Color1 );
  


private Color _color2;
public Color Color2

  get  return _color2; 
  set
  
    _color2 = value;
    this.NotifyPropertyChanged( x => x.Color2 );
  


private Color _borderColor;
public Color BorderColor

  get  return _borderColor; 
  set
  
    _borderColor = value;
    this.NotifyPropertyChanged( x => x._borderColor );
  

转换器:

public class ColorToBrushConverter : IValueConverter 
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) 
  System.Drawing.Color col = (System.Drawing.Color) value;
  Color c = Color.FromArgb( col.A, col.R, col.G, col.B );
  return new SolidColorBrush( c );


public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) 
  SolidColorBrush c = (SolidColorBrush) value;
  System.Drawing.Color col = System.Drawing.Color.FromArgb( c.Color.A, c.Color.R, c.Color.G, c.Color.B );
  return col;

【问题讨论】:

“现在为什么这不起作用” - 你怎么知道它不起作用?例如,是什么让您认为这是一个绑定错误而不是转换器中的异常?请提供有关该错误的更多信息。 就是这样,输出窗口中没有错误 + 它正在无错误地命中转换器。 如果它击中转换器,那么绑定应该工作。你也可以发布 ColorToBrushConverter 吗? 这也是我的想法,但第一次尝试 (ColorCollection) 是使用相同的转换器并且它正在工作。我已经用转换器更新了我的问题 好吧,在第二种情况下,您将绑定到GradientStop.Color,即 System.Windows.Media.Color 而不是 System.Drawing.Color。所以你的转换器应该抛出强制转换异常。 【参考方案1】:

作为Shawn Wildermuth states:

GradientStop 不是从 FrameworkElement 派生的,因此不能进行数据绑定。

解决方法是 FrameworkElement 的 the clever use of Tag property。最后,受到rmoore's answer 的启发,我最终得到了这个解决方案:

XAML

<ComboBox x:Name="colorCombo2" Height="25" ItemsSource="Binding ColorCollection" HorizontalAlignment="Right" Margin="5" Width="110">
  <ComboBox.ItemTemplate>
    <DataTemplate>
      <Grid>
        <Grid.Resources>
          <local:ColorToBrushConverter x:Key="ColorToBrushConverter"/>
        </Grid.Resources>
        <Border Height="20" Width="Binding ElementName=colorCombo2, Path=Width" 
                BorderThickness="1"
                BorderBrush="Binding BorderColor, Converter=StaticResource ColorToBrushConverter">
          <Border.Background>
            <LinearGradientBrush EndPoint="0.504,1.5" StartPoint="0.504,0.03">
              <GradientStop Color="Binding ElementName=Border1, Path=Tag" Offset="0" />
              <GradientStop Color="Binding ElementName=Border2, Path=Tag" Offset="0.567" />
            </LinearGradientBrush>
          </Border.Background>
        </Border>
        <Grid Visibility="Collapsed">
          <FrameworkElement Tag="Binding Color1" x:Name="Border1" />
          <FrameworkElement Tag="Binding Color2" x:Name="Border2" />
        </Grid>
      </Grid>
    </DataTemplate>
  </ComboBox.ItemTemplate>
</ComboBox>

ViewModel(与 OP 的 ViewModel 完全一致)

public partial class MainWindow6 : Window, INotifyPropertyChanged 
    public MainWindow6() 
        DataContext = this;
        InitializeComponent();
        var colors = new Collection<ColorGradientHelper>();
        colors.Add(new ColorGradientHelper 
            BorderColor = Colors.Orange,
            Color1 = Colors.Purple,
            Color2 = Colors.White
        );

        colors.Add(new ColorGradientHelper 
            BorderColor = Colors.Orange,
            Color1 = Colors.Black,
            Color2 = Colors.Yellow
        );
        ColorCollection = colors;
    

    private Collection<ColorGradientHelper> _colorCollection;

    public Collection<ColorGradientHelper> ColorCollection 
        get 
            return _colorCollection;
        
        set 
            _colorCollection = value;
            OnPropertyChanged();
        
    

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    

输出看起来像这样:

【讨论】:

FrameworkElement 不需要绑定它的 DependencyObject 否则很好的答案 你引用说你不能绑定任何不是从框架元素派生的东西,实际上它是启用绑定所需的更高级别的 DependencyObject,这就是为什么你甚至可以绑定到触发器虽然它们不是 FrameworkElement @MikeT,等等,但是 GradientStop 确实派生自 DependencyObject... GradientStop -> Animatable -> Freezable -> DependencyObject 是的,否则您无法将 GradientStop.Color 绑定到 FrameworkElement .Tag

以上是关于WPF 组合框颜色绑定问题的主要内容,如果未能解决你的问题,请参考以下文章

组合框中的 WPF 数据绑定彩色项目

WPF 组合框禁用背景颜色

如何在双向绑定组合框(WPF)上调用异步操作

DataGrid 数据绑定/更新中的 WPF 组合框不起作用

WPF MVVM:组合框 SelectedValue 绑定

WPF 组合框和数据绑定到其他类