因一个小项目被要求用wpf实现,在这之前没使用过wpf,有些东西的实现方式不甚了解,只能一边摸索学习一边写代码。正好其中有一个省市县级联的需求,百度了一圈也没找到满足需要的,于是自己动手实现了下。在这里整理记录下实现过程,做个备忘。
先看效果
view xaml代码
把省份的ItemsSource绑定ProvinceList,然后给城市的ItemsSource绑定到ElementName=省的SelectedItem上,同样县区的ItemsSource绑定到ElementName=市的SelectedItem上。
<Window x:Class="wpfdemo.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:wpfdemo.Views"
mc:Ignorable="d"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Height="300" Width="530" Title="demo" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="120"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Height="23" HorizontalAlignment="Right" Text="省:" VerticalAlignment="Top" />
<ComboBox Grid.Column="1" Height="23" Width="120" HorizontalAlignment="Left" Name="Province" ItemsSource="{Binding ProvinceList}" Text="{Binding Province}" DisplayMemberPath="Name" VerticalAlignment="Top" />
<TextBlock Grid.Column="2" Height="23" HorizontalAlignment="Right" Text="市:" VerticalAlignment="Top" />
<ComboBox Grid.Column="3" Height="23" HorizontalAlignment="Left" Text="{Binding City}" Name="City" ItemsSource="{Binding SelectedItem.Citys, ElementName=Province}" DisplayMemberPath="Name" VerticalAlignment="Top" Width="120" />
<TextBlock Grid.Column="4" Height="23" HorizontalAlignment="Right" Text="县区:" VerticalAlignment="Top" RenderTransformOrigin="3.5,0.662" />
<ComboBox Grid.Column="5" Height="23" HorizontalAlignment="Left" Text="{Binding County}" Name="County" ItemsSource="{Binding SelectedItem.Countys, ElementName=City}" DisplayMemberPath="Name" VerticalAlignment="Top" Width="120" />
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90"></ColumnDefinition>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="350"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Height="30" Width="100" Command="{Binding GetData}" Grid.ColumnSpan="2" Margin="10,0,10,0" >获取数据</Button>
<TextBox Grid.Column="2" Height="30" Text="{Binding txtData}" Width="350" Grid.ColumnSpan="2"></TextBox>
</Grid>
</Grid>
</Window>
viewmodel代码
首先定义三个类,分别表示省、市、县三级。除了各自都有Name属性外,其中省中包含了市的list,市中包含了县的list。
/// <summary>
/// 县/区
/// </summary>
public class County
{
public string Name { get; set; }
}
/// <summary>
/// 市
/// </summary>
public class City
{
public string Name { get; set; }
public List<County> Countys { get; set; }
}
/// <summary>
/// 省
/// </summary>
public class Province
{
public string Name { get; set; }
public List<City> Citys { get; set; }
}
定义一个ProvinceList用于ItemsSource绑定,并通过InitData方法对ProvinceList进行赋值。这里省市县数据通过网上下载的一个xml充当数据源。
public List<Province> ProvinceList { set; get; }
public MainWindowViewModel()
{
InitData();
}
/// <summary>
/// 初始化数据
/// </summary>
void InitData()
{
XmlDocument doc = new XmlDocument();
string path= ".\\ProvinceCode.xml";
XmlNodeList cities, counties = null;
doc.Load(path);
XmlNode provinces = doc.SelectSingleNode("/root");
ProvinceList = new List<Province>();
Province p = new Province();
City c = new City();
County a = new County();
foreach (XmlNode province in provinces.ChildNodes)
{
p = new Province();
p.Name = province.Attributes["Name"].Value;
path= string.Format("root/Province[@Name='{0}']/City", province.Attributes["Name"].Value);
cities = doc.SelectNodes(path);
p.Citys = new List<City>();
foreach (XmlNode city in cities)
{
c = new City();
c.Name = city.Attributes["Name"].Value;
a = new County();
path = string.Format("root/Province[@Name='{0}']/City[@Name='{1}']/County",
province.Attributes["Name"].Value, city.Attributes["Name"].Value);
c.Countys = new List<County>();
counties = doc.SelectNodes(path);
if (counties.Count == 0)
{
a.Name = "--请选择--";
c.Countys.Add(a);
}
else
{
foreach (XmlNode county in counties)
{
a = new County();
a.Name = county.Attributes["Name"].Value;
c.Countys.Add(a);
}
}
p.Citys.Add(c);
}
ProvinceList.Add(p);
}
}
至此已实现了wpf的省市县的级联,接下来要取到想要的数据,需求还有要取到每个市的区号,也很简单。
private DelegateCommand _GetData = null;
public DelegateCommand GetData => _GetData ?? (_GetData = new DelegateCommand(GetData_Click));
void GetData_Click()
{
if (County == "")
{
txtData = "请先选择省、市、县";
return;
}
string targetParm = string.Format("root/Province/City[@Name='{0}']", City);//
XmlDocument doc = new XmlDocument();
string path= ".\\ProvinceCode.xml";
doc.Load(path);
XmlNode targetNode = doc.SelectSingleNode(targetParm);
string areacode = targetNode.Attributes["areacode"].Value;
txtData = string.Format("省份:{0},城市:{1},县/区:{2},区号:{3}", Province, City, County, areacode);
}