The GradientBrush
(baseclass of LinearGradientBrush
) is defined with [ContentProperty("GradientStops")]
, which means, that the GradientStopCollection
can be either set directly as content or explicitely as GradientStops
property.
So you can define a GradientStopCollection
in resources or code behind and then bind it to your brush.
A little example XAML:
<Grid x:Name="grid1">
<Rectangle Width="30" Height="200" Margin="20">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"
GradientStops="{Binding}">
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
Code Behind:
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
GradientStopCollection c = new GradientStopCollection();
c.Add(new GradientStop(Colors.Red, 0.0));
c.Add(new GradientStop(Colors.Green, 0.5));
c.Add(new GradientStop(Colors.Yellow, 1.0));
grid1.DataContext = c;
}
I don't think you can manually add/remove individual collection items without code behind, but as said, you should be able to define / replace the whole collection in XAML as well.
Edit
So let's suppose you want to decouple your viewmodel a bit more:
public class GradientTransferObject
{
public Color Color { get; set; }
public double Offset { get; set; }
}
// ....
public ObservableCollection<GradientTransferObject> Gradients { get; set; }
Now there is a need to translate the source items into an GradientStopCollection
. This can be done with something similar to a CollectionViewSource
- an object that can be hosted as resource, takes an items source and provides an item collection.
public class GradientProvider : Freezable
{
// the resulting items collection
public GradientStopCollection GradientItems
{
get { return (GradientStopCollection)GetValue(GradientItemsProperty); }
private set { SetValue(GradientItemsPropertyKey, value); }
}
private static readonly DependencyPropertyKey GradientItemsPropertyKey =
DependencyProperty.RegisterReadOnly("GradientItems", typeof(GradientStopCollection), typeof(GradientProvider), new PropertyMetadata(null));
public static readonly DependencyProperty GradientItemsProperty = GradientItemsPropertyKey.DependencyProperty;
// the items source from viewmodel data
public IEnumerable<GradientTransferObject> GradientItemsSource
{
get { return (IEnumerable<GradientTransferObject>)GetValue(GradientItemsSourceProperty); }
set { SetValue(GradientItemsSourceProperty, value); }
}
public static readonly DependencyProperty GradientItemsSourceProperty =
DependencyProperty.Register("GradientItemsSource", typeof(IEnumerable<GradientTransferObject>), typeof(GradientProvider),
new PropertyMetadata(null, new PropertyChangedCallback(OnItemsSourceChanged)));
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var self = d as GradientProvider;
if (e.OldValue == e.NewValue)
{
return;
}
if (e.OldValue is ObservableCollection<GradientTransferObject>)
{
var c = e.OldValue as ObservableCollection<GradientTransferObject>;
c.CollectionChanged -= self.CollectionChanged;
}
if (e.NewValue is ObservableCollection<GradientTransferObject>)
{
var c = e.NewValue as ObservableCollection<GradientTransferObject>;
c.CollectionChanged += self.CollectionChanged;
}
self.UpdateItems();
}
private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdateItems();
}
private void UpdateItems()
{
GradientItems = new GradientStopCollection(GradientItemsSource.Select(x => new GradientStop(x.Color, x.Offset)));
}
protected override Freezable CreateInstanceCore()
{
return new GradientProvider();
}
}
The updated xaml example:
<Grid x:Name="grid1">
<Grid.Resources>
<local:GradientProvider x:Key="gradientSource" GradientItemsSource="{Binding}"/>
</Grid.Resources>
<Rectangle Width="30" Height="200" Margin="20">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"
GradientStops="{Binding GradientItems,Source={StaticResource gradientSource}}">
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Button VerticalAlignment="Top" HorizontalAlignment="Left" Margin="5" Content="AddGradient" Click="Button_Click"/>
</Grid>
The updated code, dynamically changing the gradient collection on button click:
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Gradients = new ObservableCollection<GradientTransferObject>()
{
new GradientTransferObject{ Color = Colors.Red, Offset = 0.0},
new GradientTransferObject{ Color = Colors.Yellow, Offset = 1.0},
};
grid1.DataContext = Gradients;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Gradients.Add(new GradientTransferObject { Color = Colors.Green, Offset = 0.5 });
}
So as you see, you are free to take it easy with direct usage of GradientStopCollection
in the viewmodel or go for full abstraction where your viewmodel source and your view work on completely different data types.