//WebAPI
//D:\C\WebApplication6\Controllers\CountyController.cs
using CsvHelper;
using CsvHelper.Configuration;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Globalization;
namespace WebApplication6.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CountyController : ControllerBase
{
private static List<CountyModel> countyList = new List<CountyModel>();
private static List<string> stateList = new List<string>();
static CountyController()
{
string csvFile = @"uscounties.csv";
ReadDataFromCSV(csvFile);
}
public CountyController()
{
}
private static void ReadDataFromCSV(string csvFile)
{
if (!System.IO.File.Exists(csvFile))
{
return;
}
string csvStr = System.IO.File.ReadAllText(csvFile);
using (StringReader sr = new StringReader(csvStr))
{
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
PrepareHeaderForMatch = args => args.Header.ToLower(),
MissingFieldFound = null,
HeaderValidated = null
};
using(var reader=new CsvReader(sr,config))
{
countyList = reader.GetRecords<CountyModel>().ToList();
stateList = countyList.Select(x => x.State_Name).Distinct().OrderBy(x=>x).ToList();
};
}
}
[HttpGet("GetCountyList/{stateName}")]
public List<CountyModel> GetCountyList(string stateName)
{
return countyList.Where(x => string.Equals(x.State_Name, stateName, StringComparison.InvariantCultureIgnoreCase)).OrderBy(x=>x.County).ToList();
}
[HttpGet("GetStateList")]
public List<string> GetStateList()
{
return stateList;
}
}
public class CountyModel
{
public string County { get; set; }
public string County_Ascii { get; set; }
public string County_Full { get; set; }
public string County_Fips { get; set; }
public string State_Name { get; set; }
public double Lat { get; set; }
public string Lng { get; set; }
public long Population { get; set; }
}
}
//D:\C\WebApplication6\Program.cs
namespace WebApplication6
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseKestrel(x =>
{
x.ListenLocalhost(5000);
x.ListenLocalhost(5001, o =>
{
o.UseHttps();
});
});
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
//app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}
//WPF
//D:\C\WpfApp15\MainWindow.xaml
<Window x:Class="WpfApp15.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:WpfApp15"
mc:Ignorable="d"
Title="{Binding MainTitle}" WindowState="Maximized">
<Window.DataContext>
<local:MainVM/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0"
BorderBrush="LightBlue"
BorderThickness="2"
Margin="5"
ItemsSource="{Binding StateCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedState,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="FontSize" Value="30"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="FontWeight" Value="ExtraBold"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="ExtraBold"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<DataGrid Grid.Column="1"
BorderBrush="LightBlue"
BorderThickness="2"
Margin="5"
ItemsSource="{Binding CountyCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="True"
CanUserReorderColumns="False"
CanUserAddRows="False"
IsReadOnly="True"
UseLayoutRounding="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
VirtualizingPanel.CacheLengthUnit="Item"
VirtualizingPanel.CacheLength="5,5"
ScrollViewer.CanContentScroll="True"
ScrollViewer.IsDeferredScrollingEnabled="True">
<DataGrid.ItemContainerStyle>
<Style TargetType="DataGridRow">
<Setter Property="FontSize" Value="30"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="ExtraBold"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.ItemContainerStyle>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Background" Value="White"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="ExtraBold"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
</Grid>
</Window>
//D:\C\WpfApp15\MainWindow.xaml.cs
using Newtonsoft.Json;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Net.Http;
using System.Runtime.CompilerServices;
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.Navigation;
using System.Windows.Shapes;
namespace WpfApp15
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class MainVM : INotifyPropertyChanged
{
string stateUrl = "https://localhost:5001/api/county/getstatelist";
string countyUrl = "https://localhost:5001/api/county/getcountylist/";
static HttpClient client = new HttpClient()
{
Timeout = TimeSpan.FromHours(1)
};
public MainVM()
{
if (!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
{
_ = LoadStateListAsync();
}
}
private async Task LoadStateListAsync()
{
try
{
string stateStr = await client.GetStringAsync(stateUrl);
if (!string.IsNullOrWhiteSpace(stateStr))
{
var stateList = JsonConvert.DeserializeObject<List<string>>(stateStr);
if (stateList != null && stateList.Any())
{
StateCollection = new ObservableCollection<string>(stateList);
SelectedState = StateCollection.FirstOrDefault();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex?.Message);
}
}
private ObservableCollection<string> stateCollection;
public ObservableCollection<string> StateCollection
{
get
{
return stateCollection;
}
set
{
if (value != stateCollection)
{
stateCollection = value;
OnPropertyChanged();
}
}
}
private string selectedState;
public string SelectedState
{
get
{
return selectedState;
}
set
{
if (value != selectedState)
{
selectedState = value;
OnPropertyChanged();
OnSelectedStateChanged();
}
}
}
private async Task OnSelectedStateChanged()
{
string countyStr = await client.GetStringAsync($"{countyUrl}{SelectedState}");
var countyList = JsonConvert.DeserializeObject<List<CountyModel>>(countyStr);
if(countyList!=null && countyList.Any())
{
CountyCollection = new ObservableCollection<CountyModel>(countyList);
}
}
private ObservableCollection<CountyModel> countyCollection;
public ObservableCollection<CountyModel> CountyCollection
{
get
{
return countyCollection;
}
set
{
if (value != countyCollection)
{
countyCollection = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propName = "")
{
var handler = Volatile.Read(ref PropertyChanged);
if (handler == null)
{
return;
}
handler(this, new PropertyChangedEventArgs(propName));
}
}
public class CountyModel
{
public string County { get; set; }
public string County_Ascii { get; set; }
public string County_Full { get; set; }
public string County_Fips { get; set; }
public string State_Name { get; set; }
public double Lat { get; set; }
public string Lng { get; set; }
public long Population { get; set; }
}
}
![image]()
![image]()
![image]()