Как привязать цвета GradientStop или свойство GradientStops в Silverlight?
Я хочу иметь возможность иметь динамический градиент в 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, у нее также возникает та же проблема, каково решение этой проблемы, которое:
- Позволяет изменить начало и конец градиента во время выполнения
- Работает в Silverlight 3.0 и не является решением WPF
Если есть обходной путь или в любом случае для дублирования этого поведения, это было бы приемлемо, у меня есть решения, которые работают с LinearGradients, так как я могу просто привязать кое-что свойство "Fill" к этому - однако в этой ситуации это не сработает, плюс может другие типы градиентов, которые я могу использовать, и другие, которые могут использоваться в будущем, к которым будет применяться это решение / альтернатива.
4 ответа
Проблема в том, что GradientStop не является производным от FrameworkElement, поэтому не может быть привязан к данным. К сожалению, это означает, что вы должны установить его из кода.
Чтобы действительно это произошло, у вас есть два варианта.
Свяжите отображаемые элементы Свойство Brush со свойством Brush в данных
У источника данных есть свойство, которое показывает, какую кисть вы хотите использовать для каждого элемента, и вы привязываете свойство отображаемого элемента, который берет кисть, скажем, Fill
имущество. Это работает, если набор различных значений, которые вы имели бы для пар значений Start и Stop, невелик. Вы создадите экземпляр каждой кисти для каждой пары, а затем элемент данных предоставит правильный.
Привязка отображаемых элементов к свойству Brush с помощью конвертера значений
Если значения Start и Stop имеют большую переменную, вам потребуется новый экземпляр типа Brush для каждого отображаемого элемента. В этом случае вы бы связали свойство кисти отображаемых элементов с помощью конвертера значений, например:
<Rectangle Fill="{Binding Converter={StaticResource MyBrushBuilder} }" ... >
Смотрите этот ответ для полного описания построения конвертера.
В этом случае реализация метода преобразования будет выглядеть так:
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;
}
Предостережение
Всякий раз, когда происходит связывание данных, создается целая куча кистей по одной для каждого элемента. Это может быть дорого и нежелательно. Следовательно, если этот подход с привязкой к конвертеру будет сочтен необходимым, я рекомендую вам использовать статический словарь кистей. Ключом в этом словаре будет хэш двух цветов. Вы будете создавать новую кисть только при необходимости и повторно использовать ранее созданную кисть, когда это возможно.
Подтвердили ли вы тип, используемый в качестве DataContext
где определяется ваша градиентная кисть? Как вы не указали Source
в вашей привязке, он будет использовать DataContext
по умолчанию.
Довольно старый пост, но это возможно (сейчас), так что вот мое решение. Мой 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;
}
}