WPF Custom Control, ListBox SelectedItem decides another Datagrid's ItemsSource

//D:\C\WpfApp14\Themes\Generic.xaml
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApp14">


    <Style TargetType="{x:Type local:StateCountyControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:StateCountyControl}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="4*"/>
                            </Grid.ColumnDefinitions>
                            <ListBox x:Name="PART_StateLbx"
                                     Grid.Column="0"
                                     BorderBrush="LightBlue"
                                     BorderThickness="2"
                                     Margin="5"
                                     SelectedItem="{Binding SelectedState,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
                                <ListBox.Resources>
                                    <Style TargetType="ListBoxItem">
                                        <Setter Property="FontSize" Value="30"/>
                                        <Style.Triggers>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="Foreground" Value="Blue"/>
                                                <Setter Property="FontWeight" Value="Bold"/>
                                            </Trigger>
                                            <Trigger Property="IsSelected" Value="True">
                                                <Setter Property="Foreground" Value="Red"/>
                                                <Setter Property="FontWeight" Value="ExtraBold"/>
                                            </Trigger>
                                        </Style.Triggers>
                                    </Style>
                                    
                                </ListBox.Resources>
                            </ListBox>

                            <DataGrid x:Name="PART_CountyDG"
                                      Grid.Column="1"
                                      BorderBrush="LightBlue"
                                      BorderThickness="2"
                                      Margin="5"
                                      ItemsSource="{Binding CountyCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                      VirtualizingPanel.IsVirtualizing="True"
                                      VirtualizingPanel.VirtualizationMode="Recycling"
                                      VirtualizingPanel.CacheLengthUnit="Item"
                                      VirtualizingPanel.CacheLength="5,5"
                                      UseLayoutRounding="True"
                                      ScrollViewer.CanContentScroll="True"
                                      ScrollViewer.IsDeferredScrollingEnabled="True"
                                      IsReadOnly="True"
                                      SelectionMode="Extended">
                                <DataGrid.ItemContainerStyle>
                                    <Style TargetType="DataGridRow">
                                        <Setter Property="FontSize" Value="30"/>
                                        <Style.Triggers>
                                            <Trigger Property="IsSelected" Value="True">
                                                <Setter Property="Background" Value="White"/>
                                            </Trigger>
                                        </Style.Triggers>
                                    </Style>
                                </DataGrid.ItemContainerStyle>
                                <DataGrid.CellStyle>
                                    <Style TargetType="DataGridCell">
                                        <Style.Triggers>
                                            <Trigger Property="IsSelected" Value="True">
                                                <Setter Property="Background" Value="Green"/>
                                                <Setter Property="Foreground" Value="Red"/>
                                                <Setter Property="FontWeight" Value="ExtraBold"/>
                                            </Trigger>
                                        </Style.Triggers>
                                    </Style>
                                </DataGrid.CellStyle>
                            </DataGrid>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>


//using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
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 WpfApp14
{
    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:WpfApp14"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:WpfApp14;assembly=WpfApp14"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Browse to and select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:StateCountyControl/>
    ///
    /// </summary>
    public class StateCountyControl : Control
    {
        private ListBox stateLbx;
        private DataGrid countyDg;

        static StateCountyControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(StateCountyControl), new FrameworkPropertyMetadata(typeof(StateCountyControl)));
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            var tempStateLbx = GetTemplateChild("PART_StateLbx") as ListBox;
            if (tempStateLbx != null)
            {
                stateLbx = tempStateLbx;                
                stateLbx.ItemsSource = StatesCollection;
                stateLbx.SelectedItem = SelectedState;
            }

            var tempDG = GetTemplateChild("PART_CountyDG") as DataGrid;
            if(tempDG!=null)
            {
                countyDg = tempDG;
                countyDg.ItemsSource = CountyCollection;
            }
        }



        public ObservableCollection<string> StatesCollection
        {
            get { return (ObservableCollection<string>)GetValue(StatesCollectionProperty); }
            set { SetValue(StatesCollectionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for StatesCollection.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StatesCollectionProperty =
            DependencyProperty.Register(nameof(StatesCollection), 
                typeof(ObservableCollection<string>), 
                typeof(StateCountyControl), 
                new PropertyMetadata(null));




        public string SelectedState
        {
            get { return (string)GetValue(SelectedStateProperty); }
            set { SetValue(SelectedStateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SelectedState.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedStateProperty =
            DependencyProperty.Register(nameof(SelectedState), 
                typeof(string), 
                typeof(StateCountyControl), 
                new PropertyMetadata(null));




        public ObservableCollection<CountyModel> CountyCollection
        {
            get { return (ObservableCollection<CountyModel>)GetValue(CountyCollectionProperty); }
            set { SetValue(CountyCollectionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CountyCollection.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CountyCollectionProperty =
            DependencyProperty.Register(nameof(CountyCollection), 
                typeof(ObservableCollection<CountyModel>), 
                typeof(StateCountyControl), 
                new PropertyMetadata(null));


    }


    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\WpfApp14\MainWindow.xaml
<Window x:Class="WpfApp14.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:WpfApp14"
        mc:Ignorable="d"
        Title="{Binding MainTitle}" WindowState="Maximized">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Grid>
        <local:StateCountyControl
                 StatesCollection="{Binding StatesCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 SelectedState="{Binding SelectedState,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 CountyCollection="{Binding CountyCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</Window>


//D:\C\WpfApp14\MainWindow.xaml.cs
using CsvHelper;
using CsvHelper.Configuration;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO;
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 WpfApp14
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class MainVM : INotifyPropertyChanged
    {

        private List<CountyModel> countyModelsList;
        public MainVM()
        {
            if (!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
            {
                string csvFile = @"../../../uscounties.csv";
                ParsetCSVFileToList(csvFile);
            }
        }

        private void ParsetCSVFileToList(string csvFile)
        {
            if (!File.Exists(csvFile))
            {
                return;
            }

            string csvStr = File.ReadAllText(csvFile);
            if (string.IsNullOrWhiteSpace(csvStr))
            {
                return;
            }

            try
            {
                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))
                    {
                        countyModelsList = reader.GetRecords<CountyModel>().ToList();
                        HashSet<string> statesSet = new HashSet<string>();

                        
                        StatesCollection = new ObservableCollection<string>(countyModelsList.Select(x=>x.State_Name).OrderBy(x=>x).ToList().Distinct());
                        SelectedState = StatesCollection.FirstOrDefault();
                        CountyCollection = new ObservableCollection<CountyModel>(countyModelsList.Where(x => string.Equals(x.State_Name, selectedState, StringComparison.InvariantCultureIgnoreCase)).ToList());
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex?.Message);
            }
        }

        private ObservableCollection<string> statesCollection;
        public ObservableCollection<string> StatesCollection
        {
            get
            {
                return statesCollection;
            }
            set
            {
                if (value != statesCollection)
                {
                    statesCollection = value;
                    OnPropertyChanged();
                }
            }
        }

        private string selectedState;
        public string SelectedState
        {
            get
            {
                return selectedState;
            }
            set
            {
                if(value!=selectedState)
                {
                    selectedState = value;
                    OnPropertyChanged();
                    OnSelectedStateChanged();
                }
            }
        }

        private void OnSelectedStateChanged()
        {
            CountyCollection = new ObservableCollection<CountyModel>(countyModelsList.Where(x => string.Equals(x.State_Name, SelectedState, StringComparison.InvariantCultureIgnoreCase)).OrderBy(x=>x.County).ToList());
            MainTitle = $"Selected state is {SelectedState}";
        }

        private string mainTitle;
        public string MainTitle
        {
            get
            {
                return mainTitle;
            }
            set
            {
                if(value!=mainTitle)
                {
                    mainTitle = value;
                    OnPropertyChanged();
                }
            }
        }

        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));
        }
    }   

     
}

 

 

 

 

 

 

 

image

 

 

 

 

 

 

 

 

 

 

 

image

 

 

 

 

 

 

 

 

 

 

image

 

 

 

 

image

 

posted @ 2026-09-12 19:57  FredGrit  阅读(6)  评论(0)    收藏  举报