Я привязываю ItemsControl к наблюдаемой коллекции SwatchThumbnails, которая будет содержать данные для генерации прямоугольников. Прямоугольник может иметь между 1-3 цветами, связанными с ним, и должен отображать, что много цветов, когда оно отображается. Я думаю, что я понимаю, как привязать только один цвет к заполнению, но мне нужен способ привязать до трех и показать их равномерно. Как это может быть сделано?
Вот мой XAML:
<ScrollViewer x:Name="sv_Thumbnails" Grid.ColumnSpan="2" Grid.Row="1" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto">
<ItemsControl x:Name="ug_Thumbnails" ItemsSource="{Binding SwatchThumbnails, ElementName=mainWindow}">
<ItemsControl.ItemsPanel >
<ItemsPanelTemplate>
<UniformGrid Columns="6" RenderTransformOrigin="0,0.5" Cursor="Hand">
<Rectangle Width="50" Height="50" Fill="{Binding Color}" Margin="0 0 5 0" />
</UniformGrid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
Я изначально вставлял форму прямоугольника в UniformGrid через код С#, поэтому у меня есть исходный код, который был написан для разделения цветов. В принципе, это был исходный код, который я создал для создания прямоугольников:
System.Windows.Shapes.Rectangle swatch = new System.Windows.Shapes.Rectangle();
swatch.Width = 50;
swatch.Height = 50;
swatch.Margin = new Thickness(0, 5, 5, 0);
swatch.StrokeThickness = 1;
swatch.Stroke = System.Windows.Media.Brushes.Gray;
swatch.Name = "s_" + _name.ToString();
double groupsize = 100 / _colors.Count();
DrawingBrush blackBrush = new DrawingBrush();
DrawingGroup checkersDrawingGroup = new DrawingGroup();
List<SolidColorBrush> brushes = _colors;
double location = 0;
for (int i = 0; i < _colors.Count(); i++)
{
GeometryDrawing drawing = new GeometryDrawing(brushes[i], null,
new RectangleGeometry(new Rect(0, location, groupsize, groupsize)));
checkersDrawingGroup.Children.Add(drawing);
location += groupsize;
}
blackBrush.Drawing = checkersDrawingGroup;
swatch.Fill = blackBrush;
swatch.MouseUp += new MouseButtonEventHandler(loadSwatchResources);
И наконец, здесь можно увидеть мою коллекцию и определение эскизов образца.
private ObservableCollection<SwatchThumbnail> swatchThumbnails = new ObservableCollection<SwatchThumbnail>();
public ObservableCollection<SwatchThumbnail> SwatchThumbnails
{
get { return swatchThumbnails; }
set { swatchThumbnails = value; }
}
public class SwatchThumbnail : INotifyPropertyChanged
{
public string name { get; set; }
public List<Color> colors { get; set; }
public bool selected { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
Фон, который вы хотите для каждого миниатюры, на самом деле выглядит как вертикальный LinearGradientBrush
поэтому лучшим выбором здесь является LinearGradientBrush
, а не DrawingBrush
который слишком сложный (и излишний) для этого сценария. Вам понадобится свойство Colors
(с реализованным INotifyPropertyChanged), в котором находится диапазон цветов. Чтобы преобразовать это в LinearGradientBrush
, вам нужен Converter
. Я понимаю, что все цветовые полосы должны иметь равную высоту (и полную ширину). К счастью, Offset
в LinearGradientBrush относительное (по некоторому отношению) к всей высоте, поэтому нам не нужна информация о фактической высоте соответствующего прямоугольника. Вот класс конвертера:
public class ColorsToLinearGradientBrushConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture){
var colors = (List<Color>) value;
var brush = new LinearGradientBrush(){ StartPoint = new Point(),
EndPoint = new Point(0,1)};
var w = 1d / colors.Count;
for(var i = 0; i < colors.Count - 1; i++){
var offset = w * (i+1);
var stop1 = new GradientStop(colors[i], offset);
var stop2 = new GradientStop(colors[i+1], offset);
brush.GradientStops.Add(stop1);
brush.GradientStops.Add(stop2);
}
return brush;
}
//this way back is not needed (bind OneWay)
public object ConvertBack(object value Type targetType, object parameter,
CultureInfo culture){
throw new NotImplementedException();
}
}
Обратите внимание, что свойство Colors
должно иметь тип List<Color>
(ваше исходное свойство имеет тип List<SolidColorBrush>
).
Определите свой конвертер как некоторый ресурс в своем XAML и обычно используйте его для привязки (надеюсь, вы это знаете). Вот код XAML:
<ScrollViewer x:Name="sv_Thumbnails" Grid.ColumnSpan="2" Grid.Row="1"
VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto">
<ScrollViewer.Resources>
<local:ColorsToLinearGradientBrushConverter x:Key="brushConverter"/>
</ScrollViewer.Resources>
<ItemsControl x:Name="ug_Thumbnails" ItemsSource="{Binding SwatchThumbnails,
ElementName=mainWindow}">
<!--ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="6" RenderTransformOrigin="0,0.5" Cursor="Hand">
</UniformGrid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel-->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Width="50" Height="50" Fill="{Binding Colors,
Converter={StaticResource brushConverter}}"
Margin="0 0 5 0" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Обратите внимание, что здесь вы должны использовать некоторый ItemTemplate
, ваш оригинальный XAML имеет только ItemsPanel
который изменяет весь контейнер элементов. Если это то, что вы хотите, просто укажите эту панель как обычно, но помните, что она просто связана с тем, как упорядочивать и компоновать элементы. Это означает, что мы не можем привязывать Background для каждого элемента, основываясь только на этом.
Обновление: я предположил, что вы правильно SwatchThumbnail
. Но похоже, что нет. Поэтому попробуйте выполнить следующую реализацию, чтобы увидеть, работает ли она:
public class SwatchThumbnail : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string prop){
var handler = PropertyChanged;
if(handler != null) handler(this, new PropertyChangedEventArgs(prop));
}
string _name;
public string name {
get { return _name;}
set {
if(_name != value) {
_name = value;
OnPropertyChanged("name");
}
}
}
List<SolidColorBrush> _colors;
public List<SolidColorBrush> colors {
get {
return _colors;
}
set {
_colors = value;
OnPropertyChanged("colors");
}
}
bool _selected;
public bool selected {
get {
return selected;
}
set {
if(_selected != value){
_selected = value;
OnPropertyChanged("selected");
}
}
}
}
Насколько я знаю, самым простым способом было бы использовать DrawingBrush
вместо SolidColorBrush
.
Ваш DrawingBrush будет описывать шаблон, который вы используете для заполнения Rectangle (в вашем случае вы будете использовать ваши три кисти SolidColor для рисования содержимого DrawingBrush). Свойство Fill
вашего прямоугольника должно быть привязано к DrawingBrush.
См. Описание того, как использовать DrawingBrush как Rectangle здесь.