Изображения в списке в WPF MVVM - PullRequest
2 голосов
/ 08 августа 2010

У меня вопрос о том, как лучше всего добиться чего-то в WPF MVVM.У меня есть в моей ViewModel ряд целых чисел.Для примера, давайте назовем их:

public int Yellow
{
    get;set;
}
public int Red
{
    get;set;
}
public int Green
{
    get;set;
}

У меня также есть несколько небольших изображений, которые очень просты: красный круг, желтый круг и зеленый круг.Идея состоит в том, чтобы иметь область на виде с множеством этих изображений, основываясь на вышеуказанных свойствах.Поэтому, если этот экземпляр модели представления имеет 3 желтых, 2 красных и 1 зеленый, я хочу 6 изображений в моем ListBox, 3 из желтого круга, 2 из красного и 1 из зеленого.Прямо сейчас у меня это работает, но я использую некоторый очень неуклюжий код, где я строю список изображений в ViewModel, используя уродливый цикл for.Есть ли более элегантный способ выполнить эту задачу в WPF?В идеале я бы не хотел ссылаться на изображение в ViewModel вообще ...

Ответы [ 2 ]

5 голосов
/ 08 августа 2010

Вы можете использовать ImageBrush , чтобы наложить прямоугольник на изображение и привязать ширину прямоугольника к числу копий изображения, которое вы хотите. Примерно так:

<StackPanel Orientation="Horizontal">
    <StackPanel.LayoutTransform>
        <ScaleTransform ScaleX="20" ScaleY="20"/>
    </StackPanel.LayoutTransform>
    <Rectangle Width="{Binding Yellow}" Height="1">
        <Rectangle.Fill>
            <ImageBrush
                ImageSource="Yellow.png"
                Viewport="0,0,1,1"
                ViewportUnits="Absolute"
                TileMode="Tile"/>
        </Rectangle.Fill>
    </Rectangle>
    <Rectangle Width="{Binding Red}" Height="1">
        <Rectangle.Fill>
            <ImageBrush
                ImageSource="Red.png"
                Viewport="0,0,1,1"
                ViewportUnits="Absolute"
                TileMode="Tile"/>
        </Rectangle.Fill>
    </Rectangle>
    <Rectangle Width="{Binding Green}" Height="1">
        <Rectangle.Fill>
            <ImageBrush
                ImageSource="Green.png"
                Viewport="0,0,1,1"
                ViewportUnits="Absolute"
                TileMode="Tile"/>
        </Rectangle.Fill>
    </Rectangle>
</StackPanel>

Обновление: Как указал Рэй в своем комментарии, если вы просто пытаетесь нарисовать круги, вы получите лучшее масштабирование при использовании DrawingBrush, чем при использовании Image:

<StackPanel Orientation="Horizontal">
    <StackPanel.LayoutTransform>
        <ScaleTransform ScaleX="20" ScaleY="20"/>
    </StackPanel.LayoutTransform>
    <StackPanel.Resources>
        <EllipseGeometry x:Key="Circle" RadiusX="1" RadiusY="1"/>
    </StackPanel.Resources>
    <Rectangle Width="{Binding Yellow}" Height="1">
        <Rectangle.Fill>
            <DrawingBrush ViewportUnits="Absolute" TileMode="Tile">
                <DrawingBrush.Drawing>
                    <GeometryDrawing
                        Brush="Yellow"
                        Geometry="{StaticResource Circle}"/>
                </DrawingBrush.Drawing>
            </DrawingBrush>
        </Rectangle.Fill>
    </Rectangle>
    <!-- etc. -->
0 голосов
/ 13 августа 2010

Можно использовать ValueConverter . Это очень гибкий, отделенный и помогает сделать xaml простым. Вот код для такого преобразователя значения:

public class ImageCountValueConverter : IValueConverter{
    public string ImagePath {
        get;
        set;
    }
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        if(null == value){
            return Enumerable.Empty<string>();
        } else if (value is int) {
            List<string> list = new List<string>();
            int v = (int)value;
            for (int i = 0; i < v; i++) {
                if (parameter is string) {
                    list.Add((string)parameter);
                } else {
                    list.Add(ImagePath);
                }
            }
            return list;
        } else {
            Type t = value.GetType();
            throw new NotSupportedException("The \"" + t.Name+ "\" type is not supported");
        }
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        throw new NotImplementedException();
    }
}

Разметка будет выглядеть так:

<StackPanel>
  <ItemsControl ItemsSource="{Binding Yellow,Converter={StaticResource ImageCount_ValueConverter},ConverterParameter=/image/yellow.png}" >
      <ItemsControl.ItemTemplate>
          <DataTemplate>
              <Image Source="{Binding}" Stretch="None"/>
          </DataTemplate>
      </ItemsControl.ItemTemplate>
  </ItemsControl>

  <ItemsControl ItemsSource="{Binding Red,Converter={StaticResource ImageCount_ValueConverter},ConverterParameter=/image/red.png}" >

  ...

Декларация будет выглядеть примерно так:

  <Window.Resources>
        <local:ImageCountValueConverter x:Key="ImageCount_ValueConverter" ImagePath="/image/sampleImage.png"/>            
    </Window.Resources>

Опция

В зависимости от ваших требований вы также можете расширить его или изменить его для работы с ImageSource вместо строк или даже предоставить List<Brush> в качестве вывода, а затем использовать фигуру в вашем шаблоне данных, где Brush устанавливается через привязку.

...