【问题标题】:How to bind GradientStop Colours or GradientStops Property in Silverlight?如何在 Silverlight 中绑定 GradientStop 颜色或 GradientStops 属性?
【发布时间】:2010-12-03 14:07:37
【问题描述】:

我希望能够在 Silverlight 中拥有动态渐变,如下所示:

<RadialGradientBrush GradientOrigin="0.20,0.5" Center="0.25,0.50" 
                     RadiusX="0.75" RadiusY="0.5">
  <GradientStop Color="{Binding Path=GradientStart}" Offset="0" />
  <GradientStop Color="{Binding Path=GradientEnd}" Offset="1" />
</RadialGradientBrush>

我正在绑定两个返回“颜色”类型的属性,但是我总是收到以下消息:

AG_E_PARSER_BAD_PROPERTY_VALUE

如果我尝试绑定到 GradientStop Collection 这也有同样的问题,这个问题的解决方案是什么:

  1. 允许在运行时更改渐变的开始和结束
  2. 在 Silverlight 3.0 中工作,不是 WPF 解决方案

如果有解决方法或无论如何要复制此行为,这是可以接受的,我有与 LinearGradients 一起使用的解决方案,因为我可以将某些“填充”属性绑定到此 - 但是在这种情况下不起作用,另外,我可能会使用其他渐变类型,并且将来可能会使用此解决方案/替代方案的其他渐变类型。

【问题讨论】:

    标签: silverlight xaml binding gradient gradientstop


    【解决方案1】:

    问题是 GradientStop 不是从 FrameworkElement 派生的,因此不能进行数据绑定。不幸的是,这意味着您必须从代码中设置它。

    【讨论】:

    • 感谢您的回答,我听说过从 FrameworkElement 派生的项目,所以这不是 - 猜测颜色会相同 - 现在我明白了,我将在代码中将其设置为真的没有其他选择 - 也许 Silverlight 4 会允许这样做?
    • 为此 +1。我原本打算回答这是不可能的,因为Color 不是依赖属性。对 .NET Reflector 的简要介绍表明它遵循该模式,所以我很困惑。原来Color 是通过Animatable.RegisterProperty 创建的。因此,即使它不可绑定,它也是可动画的。
    • @RoguePanetiod:实际上事情比这要困难一些。通常,画笔是一个引用对象,不会为每个项目创建画笔的新实例。因此,如果您修改一个项目引用的画笔,您很可能会发现您正在修改所有其他项目的画笔引用。
    【解决方案2】:

    要真正做到这一点,您有两个选择。

    将显示项的 Brush 属性绑定到数据中的 Brush 属性

    让数据源带有一个属性,该属性显示您要为每个项目使用哪个画笔,并绑定使用画笔的显示项目的属性,例如Fill 属性。如果您对 Start 和 Stop 值对的不同值集很小,则此方法有效。您将为每一对画笔创建一个实例,然后数据项将显示正确的画笔。

    使用值转换器绑定显示项的 Brush 属性

    如果您的 Start 和 Stop 值更多变量,您将需要为每个显示的项目创建一个 Brush 类型的新实例。在这种情况下,您将使用值转换器绑定显示项目画笔属性,例如:-

     <Rectangle Fill="{Binding Converter={StaticResource MyBrushBuilder} }" ... >
    

    有关构建转换器的完整描述,请参阅此answer

    在这种情况下,虽然您的转换方法实现看起来像这样:-

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
      YourItemsType item = (YourItemsType)value;
    
      var start = new GradientStop();
      start.Offset = 0;
      start.Color = item.GradientStart;
    
      var stop = new GradientStop();
      stop.Offset = 1;
      stop.Color = item.GradientStop;
    
      var result = new RadialGradientBrush();
      result.GradientOrigin = new Point(0.20, 0.5);
      result.Center = new Point(0.25, 0.5);
      result.RadiusX = 0.75;
      result.RadiusY = 0.5;
      result.GradientStops = new GradientStopCollection();
      result.GradientStops.Add(start);
      result.GradientStops.Add(stop);
    
      return result;
    }
    

    警告

    每当发生数据绑定时,都会为每个项目创建一大堆画笔。这可能是昂贵且不受欢迎的。因此,如果认为这种绑定转换器方法是必要的,那么我建议您使用静态画笔字典。这个字典的关键是这两种颜色的哈希值。您只会在必要时创建一个新画笔,并尽可能重复使用以前创建的画笔。

    【讨论】:

    • 当心这个答案中的拼写错误:start.Offset 和 start.Color 设置了两次。还有一些缺少的半列。
    【解决方案3】:

    您是否确认用作定义渐变画笔的DataContext 的类型?由于您没有在绑定中指定Source,因此默认情况下它将使用DataContext

    【讨论】:

    • 这很好,因为其他项目(例如 SolidColorBrushes)可以毫无问题地绑定到值 - 当程序运行时会发生此错误 - 如果它说有什么问题就好了绑定类型 - 但它永远不会那么远。
    • 我已经完成了比 Silverlight 开发更多的 WPF 开发,但是当运行具有错误绑定的 WPF 应用程序时,在 Visual Studio 的“输出”面板中会吐出非常有用的消息。它们显示绑定路径、目标类型和源类型。你看到了吗?
    • 没有,但是我在转换时看到了这些消息,例如将字符串绑定到画笔,但是绑定到颜色似乎是不可能的,或者因为它永远不会绑定到渐变停止就它不接受任何绑定而言 - 这解释了错误。
    • 当我第一次阅读您的问题时,我在 .NET Reflector 中查看了 GradientStop 类,发现 Color 实际上看起来像一个依赖属性。我想知道为什么会这样,即使GradientStop 不是FrameworkElement
    【解决方案4】:

    相当旧的帖子,但它是可能的(现在),所以这是我的解决方案。我的 XAML 代码:

    <Ellipse.Resources>
        <local:ColorConverter x:Key="ColorConverter"/>
    </Ellipse.Resources>
    <Ellipse.Fill>
        <RadialGradientBrush>
            <GradientStop Color="{Binding MenuColor2, Source={x:Static p:Settings.Default}, Converter={StaticResource ColorConverter}}" Offset="1" />
            <GradientStop Color="{Binding MenuColor1, Source={x:Static p:Settings.Default}, Converter={StaticResource ColorConverter}}" Offset="0.85" />
        </RadialGradientBrush>
    </Ellipse.Fill>
    

    这是我的 C# 代码。

    [ValueConversion(typeof(System.Drawing.Color), typeof(System.Windows.Media.Color))]
    public class ColorConverter : IValueConverter
    {
    
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is System.Drawing.Color)
            {
                var clr = (System.Drawing.Color)value;
                return System.Windows.Media.Color.FromArgb(clr.A, clr.R, clr.G, clr.B);
            }
            return value;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is Color)
            {
                var clr = (Color)value;
                return System.Drawing.Color.FromArgb(clr.A, clr.R, clr.G, clr.B);
            }
            return value;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-11-10
      • 2011-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-02
      • 2010-12-11
      • 1970-01-01
      • 2015-03-07
      相关资源
      最近更新 更多