ListBoxes with DataBound Images in WPF(Listbox动态加载图片的三种方式)

 

In this post, we see how we can add a DataBound image in the DataTemplate of a WPF ListBox. We experiment with three different approaches of achieving that and discuss on which one to use depending on the situation. In all cases, the image files are embedded within the application as “Resource” files. Later in this post, we will see what needs to be changed in order to support having the image files in a folder outside of the application Assembly.

 

Our object for binding will be the class named Item having the following properties:

 

public class Item
{
    public int PictureID { get; set; }
    public string Name { get; set; }
}

 

We want to display a specific image depending on the value of the property PictureID. The ListBox in the .xaml file be:

 

<ListBox ItemTemplate="{DynamicResource DataTemplateItem}" ItemsSource="{Binding Items}"/>

 

The definition of the DataTemplate for the items of the ListBox is:

 

<DataTemplate x:Key="DataTemplateItem">
    <Canvas Width="236" Height="48">
        <Image Source="{Binding ??}" Height="32" Width="32" Canvas.Left="8" Canvas.Top="8"/>
        <TextBlock Text="{Binding Name}" Canvas.Left="56" Canvas.Top="8" Width="172"/>
    </Canvas>
</DataTemplate>

 

The question in hand is what we need to put in the Binding of the Source property of the Image element in order to get the following result:

image                               image

 

The Images reside in the “Images” folder of the project and have their “Build Action” set to “Resource”.

 

1) Extending the Item class

Our first approach is to introduce a new property within the class Item that generates the appropriate string for the image path within the assembly. So the new extended Item class is:

 

public class Item {
    public int PictureID { get; set; }
    public string Name { get; set; }
    public string PictureString {
        get {return "/Images/" + PictureID.ToString() + ".png";}
    }
}

 

Note the new property PictureString with its accessor calculating the appropriate image path. Now in the Source property of the DataTemplate we just need to add Source=”{Binding PictureString}”.

 

2) Using DataTemplate Triggers

A different approach that leads to the same result is not changing at all the Item class and introducing the following style in the item’s DataTemplate:

 

<DataTemplate x:Key="DataTemplateItemStyle">
    <Canvas Width="236" Height="48">
        <Image Name="ImageName" Height="32" Width="32" Canvas.Left="8" Canvas.Top="8"/>
        <TextBlock Text="{Binding Name}" Canvas.Left="56" Canvas.Top="8" Width="172"/>
    </Canvas>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding PictureID}" Value="0">
            <Setter TargetName="ImageName" Property="Source" Value="Images\0.png"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding PictureID}" Value="1">
            <Setter TargetName="ImageName" Property="Source" Value="Images\1.png"/>
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

 

In this DataTemplate, the Source property is not directly DataBound to any property. We use a DataTemplate trigger to test the value of the PictureID property and based on the result decide which image to display.

 

3) Using a Converter

The third approach uses a Converter to do the job. The converter is written as follows:

 

public class ImageConverter:IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, 
                                                        System.Globalization.CultureInfo culture) {
        return "/Images/" + value.ToString() + ".png";
    }

    public object ConvertBack(object value, Type targetType, object parameter, 
                                                             System.Globalization.CultureInfo culture){
        throw new NotImplementedException();
    }
} 

 

And the DataTemplate will become:

 

<local:ImageConverter x:Key="ImageConverter"/>
<DataTemplate x:Key="DataTemplateItemConverter">
    <Canvas Width="236" Height="48">
        <Image Source="{Binding PictureID,Converter={StaticResource ImageConverter}}" (…) />
        <TextBlock Text="{Binding Name}" Canvas.Left="56" Canvas.Top="8" Width="172"/>
    </Canvas>
</DataTemplate>

 

The Converter receives the PictureID as it arrives from the object and converts it accordingly.

 

Which approach we use?

 

If you cannot change the Item class (because it is not your code for example) you cannot use the first approach unless you create a wrapper for the class and provide the appropriate extended property. If you do not want to do this, you selection of one of the two other approaches depends on how complex your image selection logic is. If it is complicated then the Data trigger approach may be difficult or impossible to implement and then your only choice is resorting to the converter.

 

On the other hand if you can alter the properties of the Item class then you can extend your class with the new property. Sometimes, though, your image selection logic does not depend only on properties of your business object and therefore you do not want to extend your POCO entities with the general business logic of you system. If this is the case a converter is either your best choice, or an extension of the Item class in the View augmented with the appropriate logic.

 

Now if your images are not resources in the Assembly and reside somewhere in the server where you deploy your application you need to change the paths for all approaches to: “pack://siteoforigin:,,,/Images/0.png” where the “pack://siteoforigin:,,,” says “the root of the application” and then you provide the path for the image.

 

Download the project here

 

Finally in case you are wondering in the project the property IsSynchonizedWithCurrentItem=true maintains the same selection for all the three ListBoxes in the project since they are bound to the same list of Item objects.

转载于:https://www.cnblogs.com/liuzongqi/p/3473523.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个问题涉及到网页爬虫和数据存储两个方面,需要使用Python语言和相关的库来实现。 1. 网页爬虫 使用Python中的requests库发送HTTP请求获取网页内容,使用BeautifulSoup库解析HTML文档,提取需要的数据。 具体的代码可以参考如下: ``` import requests from bs4 import BeautifulSoup url = 'https://www.example.com' response = requests.get(url) html = response.text soup = BeautifulSoup(html, 'html.parser') listboxes = soup.find_all('div', {'class': 'listbox'}) titles = [] for listbox in listboxes: lis = listbox.find_all('li') for li in lis: title = li.get_text() link = li.find('a')['href'] # 点击li进入第二个页面 response2 = requests.get(link) html2 = response2.text soup2 = BeautifulSoup(html2, 'html.parser') # 获取第一个页面的title和第二个页面里class为art_con的div元素中的p中字段 title1 = soup.find('title').get_text() content = soup2.find('div', {'class': 'art_con'}).get_text() # 存入sj.txt文件中 with open('sj.txt', 'a', encoding='utf-8') as f: f.write(title1 + '\n' + content + '\n') ``` 2. 数据存储 将抓取到的数据存储到本地文件中,可以使用Python中的文件操作。 在上面的代码中,使用了with open语句打开文件,文件的写入模式为追加模式('a'),编码格式为UTF-8。每次循环抓取到一个li标签的标题和内容后,就将它们写入文件中。 需要注意的是,如果文件不存在,with open语句会自动创建文件;如果文件已存在,则会在文件末尾追加内容。如果希望每次运行时覆盖原有文件,可以改为写入模式('w')。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值