WPF MVVM中列表中的图像

WPF MVVM中列表中的图像,wpf,image,data-binding,mvvm,Wpf,Image,Data Binding,Mvvm,我有一个关于如何在WPF MVVM中最好地完成某些事情的问题。我的ViewModel中有一系列整数。为了举例,让我们称之为: public int Yellow { get;set; } public int Red { get;set; } public int Green { get;set; } 我也有一些非常简单的小图片:一个红色的圆圈,一个黄色的圆圈和一个绿色的圆圈。其思想是基于上述属性,在视图上有一个区域,其中包含许多这样的图像。所以,如果视图模型的这个实例

我有一个关于如何在WPF MVVM中最好地完成某些事情的问题。我的ViewModel中有一系列整数。为了举例,让我们称之为:

public int Yellow
{
    get;set;
}
public int Red
{
    get;set;
}
public int Green
{
    get;set;
}
我也有一些非常简单的小图片:一个红色的圆圈,一个黄色的圆圈和一个绿色的圆圈。其思想是基于上述属性,在视图上有一个区域,其中包含许多这样的图像。所以,如果视图模型的这个实例有3个黄色、2个红色和1个绿色,我希望列表框中有6个图像,3个黄色圆圈,2个红色,1个绿色。现在,我已经让它工作了,但是使用了一些非常笨拙的代码,在ViewModel中使用丑陋的for循环构建图像列表。在WPF中是否有更优雅的方法来完成此任务?理想情况下,我根本不想在ViewModel中引用图像…

您可以使用平铺图像来平铺矩形,并将矩形的宽度绑定到所需图像的副本数。大概是这样的:

<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>


更新:正如Ray在评论中指出的,如果您只是尝试绘制圆,那么使用DrawingBrush比使用图像可以获得更好的缩放效果:

<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. -->

一种可能是使用。它非常灵活、解耦,有助于简化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();
    }
}
公共类ImageCountValueConverter:IValueConverter{
公共字符串映像路径{
收到
设置
}
公共对象转换(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性){
if(null==值){
返回可枚举的.Empty();
}else if(值为int){
列表=新列表();
int v=(int)值;
对于(int i=0;i
标记如下所示:

<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而不是字符串,甚至可以提供一个
列表作为输出,然后在数据模板中使用一个形状,在该形状中通过绑定设置笔刷。

这看起来是可行的。还有其他解决方案吗?Quartermeister的解决方案基本上与我的建议(+1)相同。还有其他的解决方案,但没有一个这么干净、简单和优雅。你对他的回答不满意有什么原因吗?我确实想到了对Quartermeister解决方案的一个可能的改进:如果使用带有圆形图形的DrawingBrush,而不是带有.png文件的ImageBrush,你会获得更好的缩放效果@夸特迈斯特:如果你愿意的话,欢迎你在回答中加上这个。@Ray:说得好!他说他有图像,所以我在考虑图像文件,但如果它们真的只是圆,那么DrawingBrush会更简单。我会更新我的答案。我对答案不是太不满意,而是想进一步了解WPF的总体情况。在我的研究中,我遇到了几个可能工作的组件(值转换器、触发器、画笔等),并希望得到一系列包含不同技术的不同示例。