有关ListBox
如何拿到Source:从SQL,从XML file
SQL:一个是ObjectDataProvider
//用linq方法拿到SQL data,wrap到一个IEnumerable<Customer> public IEnumerable<Customer> GetAllCustomersAsList() { var items = from cust in this.Customers orderby cust.LastName select cust; return items.ToList(); }
//xaml里定义ObjectDataProvider 拿到这个Customer list resource <ObjectDataProvider x:Key="odpCust" ObjectType="{x:Type src:AdvWorksDataContext}" MethodName="GetTable"> <ObjectDataProvider.MethodParameters> <x:Type TypeName="src:Customer" /> </ObjectDataProvider.MethodParameters> </ObjectDataProvider>
//消费 <ListBox ItemsSource="{Binding Source={StaticResource odpCust}}" DisplayMemberPath="LastName"></ListBox>
XML file:一个是XmlDataProvider
//准备XML文件 <?xml version="1.0" standalone="yes"?> <Products> <Product> <ProductId>1</ProductId> <ProductName>PDSA .NET Productivity Framework V4.1</ProductName> <Price>5000</Price> <Logo>/Images/Framework.gif</Logo> </Product> <Product> <ProductId>2</ProductId> <ProductName>Architecting ASP.NET Applications eBook</ProductName> <Price>19.95</Price> <Logo>/Images/ArchASPNET_100.gif</Logo> </Product> <Product> <ProductId>3</ProductId> <ProductName>Fundamentals of N-Tier eBook</ProductName> <Price>19.95</Price> <Logo>/Images/FundNTier_100.gif</Logo> </Product> <Product> <ProductId>4</ProductId> <ProductName>Security for ASP.NET Developers eBook</ProductName> <Price>19.95</Price> <Logo>/Images/FundSecurity_100.gif</Logo> </Product> <Product> <ProductId>6</ProductId> <ProductName>VB.NET Fundamentals eBook</ProductName> <Price>19.95</Price> <Logo>/Images/FundVBNet_100.gif</Logo> </Product> <Product> <ProductId>7</ProductId> <ProductName>Fundamentals of SQL Server 2005</ProductName> <Price>19.95</Price> <Logo>/Images/FundSQL_100.gif</Logo> </Product> </Products>
//准备XML应用的资源 <XmlDataProvider x:Key="xmlProducts" Source="/Xml/Product.xml" XPath="Products/Product"></XmlDataProvider>
//消费XmlDataProvider <ListBox Name="lstProducts" ItemsSource="{Binding Source={StaticResource xmlProducts}}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Image Margin="8" Source="{Binding XPath=Logo}" Width="100"></Image> <Label Width="250" Content="{Binding XPath=ProductName}"></Label> <Label Width="100" Content="{Binding XPath=Price}"></Label> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
Assign Template in xaml & Dynamic change Template in Code
//后台方法定义 public IOrderedQueryable<Customer> GetAllCustomers() { var items = from cust in this.Customers orderby cust.LastName select cust; return items; }
//prepare different layout DT <Window.Resources> <ObjectDataProvider x:Key="odpCust" ObjectType="{x:Type src:AdvWorksDataContext}" MethodName="GetAllCustomers"></ObjectDataProvider> <Style TargetType="Button"> <Setter Property="Margin" Value="8"></Setter> <Setter Property="Width" Value="60"></Setter> </Style> <DataTemplate x:Key="tmplMore"> <StackPanel Orientation="Vertical" HorizontalAlignment="Left" Margin="8"> <StackPanel Orientation="Horizontal"> <Label FontSize="16" Content="{Binding Path=FirstName}"></Label> <Label Width="Auto" FontSize="16" Content="{Binding Path=LastName}"></Label> </StackPanel> <Label FontSize="12" Content="{Binding Path=EmailAddress}"></Label> </StackPanel> </DataTemplate> <DataTemplate x:Key="tmplLess"> <StackPanel Orientation="Vertical" HorizontalAlignment="Left" Margin="8"> <StackPanel Orientation="Horizontal"> <Label FontSize="16" Content="{Binding Path=FirstName}"></Label> <Label Width="Auto" FontSize="16" Content="{Binding Path=LastName}"></Label> </StackPanel> </StackPanel> </DataTemplate> </Window.Resources>
//消费ObjectDataProvider和DT //一个是ItemsSource一个是ItemTemplate <ListBox Margin="10,10,0,0" Height="300" Name="lstData" ItemsSource="{Binding Source={StaticResource odpCust}}" IsSynchronizedWithCurrentItem="True" ItemTemplate="{StaticResource tmplMore}"> </ListBox>
后台程序 runtime change DT:
//lstData可以找前台的x:name,FindResource可以找前台的x:key public partial class frmListBox2Templates : Window { public frmListBox2Templates() { InitializeComponent(); } private void btnMore_Click(object sender, RoutedEventArgs e) { DataTemplate tmpl; tmpl = (DataTemplate)this.FindResource("tmplMore"); if(tmpl != null) lstData.ItemTemplate = tmpl; } private void btnLess_Click(object sender, RoutedEventArgs e) { DataTemplate tmpl; tmpl = (DataTemplate)this.FindResource("tmplLess"); if (tmpl != null) lstData.ItemTemplate = tmpl; } }
ListBox Sorting and Filter:
首先need datasource coming back from IEnumerable<T>
use CollectionViewSource
然后才可以sort或者filter,sort可以xaml或者code,但是filter要code
xaml sort的例子
//后台程序 //Customers是GetAllCustomersAsList的一个Table //items.ToList()是因为我们要sort这个listbox,.list给了很好的支持 public IEnumerable<Customer> GetAllCustomersAsList() { var items = from cust in this.Customers orderby cust.LastName select cust; return items.ToList(); }
//ObjectDataProvider连接后台GetAllCustomersAsList返回一个可以sort的customers list //CollectionViewSource 提供了sort的一切功能,可以set CollectionViewSource.SortDescriptions //注意SortDescription 前面要加scm //可以有多个SortDescription xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" ...... <Window.Resources> <ObjectDataProvider x:Key="odpCust" ObjectType="{x:Type src:AdvWorksDataContext}" MethodName="GetAllCustomersAsList"> </ObjectDataProvider> <CollectionViewSource Source="{StaticResource odpCust}" x:Key="collCust"> <CollectionViewSource.SortDescriptions> <scm:SortDescription PropertyName="LastName" Direction="Ascending" /> <scm:SortDescription PropertyName="FirstName" Direction="Ascending" /> </CollectionViewSource.SortDescriptions> </CollectionViewSource> </Window.Resources>
coding sort的例子(两个button用来sort)
//resources里不用定义CollectionViewSource了 <Window.Resources> <ObjectDataProvider x:Key="odpCust" ObjectType="{x:Type src:AdvWorksDataContext}" MethodName="GetAllCustomersAsList"></ObjectDataProvider> </Window.Resources>
//ItemSource属性消费ObjectDataProvider,注意这里要可以sort ItemsSource must use the ToList() //两个RadioButton的Tag是重点 <Grid> <StackPanel> <GroupBox Header="Sorting Options" BorderBrush="Black" BorderThickness="1"> <StackPanel Orientation="Horizontal"> <RadioButton Name="rdoSortLast" Margin="8" Tag="LastName" IsChecked="True" Checked="SortTheData">Sort by Last Name</RadioButton> <RadioButton Name="rdoSortFirst" Margin="8" Tag="FirstName" Checked="SortTheData">Sort by First Name</RadioButton> </StackPanel> </GroupBox> <Label FontSize="16">Customers</Label> <ListBox Name="lstCustomers" Height="300" ItemsSource="{Binding Source={StaticResource odpCust}}"> <!-- ItemTemplate controls the data within each item in the ListBox --> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Vertical" HorizontalAlignment="Left" Margin="8"> <StackPanel Orientation="Horizontal"> <Label FontSize="16" Content="{Binding Path=FirstName}"></Label> <Label Width="Auto" FontSize="16" Content="{Binding Path=LastName}"></Label> </StackPanel> <Label FontSize="12" Content="{Binding Path=EmailAddress}"></Label> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </StackPanel> </Grid>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using WPFComponents; using System.ComponentModel; namespace WPFListBox { /// <summary> /// Interaction logic for frmListBoxSortUsingCode.xaml /// </summary> public partial class frmListBoxSortUsingCode : Window { public frmListBoxSortUsingCode() { InitializeComponent(); } private void SortTheData(object sender, RoutedEventArgs e) { // For sorting to work, the ItemsSource must use the ToList() if (lstCustomers != null) { ICollectionView dataView = CollectionViewSource.GetDefaultView( lstCustomers.ItemsSource); dataView.SortDescriptions.Clear(); dataView.SortDescriptions.Add( new SortDescription( (sender as RadioButton).Tag.ToString(), ListSortDirection.Ascending)); lstCustomers.ItemsSource = dataView; } } } }
code filter的例子
Filter boxlist,以Texbox里写入的字符串filter
Filter部分的代码,按查找按钮调用FilterData //=>linq的写法,cust是parameter,返回这个parameter,其是grab customer类型的对象,看他的LastName.ToLower()是否以TextBox里写的字符小写为开始的 private void FilterData() { // For Filtering to work, the ItemsSource must use the ToList() // It must be IEnumerable<Customer> if (lstCustomers != null) { ICollectionView dataView = CollectionViewSource.GetDefaultView( lstCustomers.ItemsSource); dataView.Filter = cust => ((Customer)cust).LastName.ToLower(). StartsWith(txtLast.Text.ToLower()); lstCustomers.ItemsSource = dataView; } }
ListBox里项目的Converter:从xml里拿到的item是一个xml对象,我们需要让其变成decimal然后format成C(currency:$)
//还是用XmlDataProvider compile xml data //注意是Label,用的是Content所以format要用ContentStringFormat而不是StringFormat //ContentStringFormat="{}{0:C}"这里的第一个{}是escape后面的{0:C},表示{0:C}整个看作一个string写入 //C表示format成currency但是前提是要对的type(decimal) <Window x:Class="WPFListBox.frmListBoxFormatConverter" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:src="clr-namespace:WPFComponents;assembly=WPFComponents" Title="List Box Formatting using ValueConverter" WindowStartupLocation="CenterScreen" Height="390" Width="682"> <Window.Resources> <src:XmlElementToDecimalConverter x:Key="sdConvert" /> <XmlDataProvider x:Key="xmlProducts" Source="/Xml/Product.xml" XPath="Products/Product"></XmlDataProvider> </Window.Resources> <Grid> <ListBox Name="lstProducts" ItemsSource="{Binding Source={StaticResource xmlProducts}}" IsSynchronizedWithCurrentItem="True"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Image Margin="8" Source="{Binding XPath=Logo}" Width="100"></Image> <Label Width="250" Content="{Binding XPath=ProductName}"></Label> <Label Width="100" ContentStringFormat="{}{0:C}" Content="{Binding XPath=Price, Converter={StaticResource sdConvert}}"></Label> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Window>
//看attibute,代表Convert方法,进去的是XmlElement出的是decimal using System; using System.ComponentModel; using System.Globalization; using System.Windows.Data; using System.Xml; namespace WPFComponents { [ValueConversion(typeof(XmlElement), typeof(decimal))] public class XmlElementToDecimalConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return System.Convert.ToDecimal(((XmlElement)value).InnerText); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return System.Convert.ToString(value); } } }