WPF CustomeControl Binding Collection via Binding DataCollection,RelativeSource={RelativeSource Ancestory=CustomizedControl}},

 <ComboBox ItemsSource="{Binding CategoryList,RelativeSource={RelativeSource AncestorType=local:ClassfiedItemsControl}}"
           SelectedItem="{Binding Path=SelectedCategory,RelativeSource={RelativeSource AncestorType=local:ClassfiedItemsControl},
           Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
           FontSize="30"/>

 

 

 <ItemsControl ItemsSource="{Binding BksCollection,RelativeSource={RelativeSource AncestorType=local:ClassfiedItemsControl}}"
               VirtualizingPanel.IsVirtualizing="True"
               VirtualizingPanel.VirtualizationMode="Recycling"
               VirtualizingPanel.CacheLengthUnit="Item"
               VirtualizingPanel.CacheLength="5,5"
              >

 

 

Install-Package Newtonsoft.json

 

 

//D:\C\WpfApp15\Models\BookModel.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace WpfApp15.Models
{
    public class BookModel
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public string ISBN { get; set; }
        public string CategoryName { get; set; }
        public string Comment { get; set; }
        public string Content { get; set; }
        public string Summary { get; set; }
        public string Title { get; set; }
        public string Topic { get; set; }
        public string Author { get; set; }
    }
}



//D:\C\WpfApp15\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:WpfApp15">


    <Style TargetType="{x:Type local:ClassfiedItemsControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ClassfiedItemsControl}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Border BorderBrush="Cyan"
                                BorderThickness="3"
                                Margin="10">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="4*"/>
                                </Grid.ColumnDefinitions>
                                <Border Grid.Column="0" BorderBrush="Cyan" BorderThickness="2"
                                        Margin="5">
                                    <StackPanel>
                                        <TextBlock FontSize="30"
                                                   Text="Category:"/>
                                        <ComboBox ItemsSource="{Binding CategoryList,RelativeSource={RelativeSource AncestorType=local:ClassfiedItemsControl}}"
                                                  SelectedItem="{Binding Path=SelectedCategory,RelativeSource={RelativeSource AncestorType=local:ClassfiedItemsControl},
                                                  Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                                  FontSize="30"/>
                                    </StackPanel>
                                </Border>

                                <Border BorderBrush="Cyan"
                                      BorderThickness="2"
                                      Margin="5"
                                      Grid.Column="1">
                                    <ItemsControl ItemsSource="{Binding BksCollection,RelativeSource={RelativeSource AncestorType=local:ClassfiedItemsControl}}"
                                                  VirtualizingPanel.IsVirtualizing="True"
                                                  VirtualizingPanel.VirtualizationMode="Recycling"
                                                  VirtualizingPanel.CacheLengthUnit="Item"
                                                  VirtualizingPanel.CacheLength="5,5"
                                                 >
                                        <ItemsControl.ItemsPanel>
                                            <ItemsPanelTemplate>
                                                <VirtualizingStackPanel/>
                                            </ItemsPanelTemplate>
                                        </ItemsControl.ItemsPanel>
                                        <ItemsControl.ItemTemplate>
                                            <DataTemplate>
                                                <Grid Margin="5">
                                                    <Grid.Resources>
                                                        <Style TargetType="TextBlock">
                                                            <Setter Property="FontSize" Value="30"/>
                                                            <Style.Triggers>
                                                                <Trigger Property="IsMouseOver" Value="True">
                                                                    <Setter Property="Foreground" Value="Red"/>
                                                                    <Setter Property="FontWeight" Value="ExtraBold"/>
                                                                </Trigger>
                                                            </Style.Triggers>
                                                        </Style>
                                                    </Grid.Resources>
                                                    <Grid.RowDefinitions>
                                                        <RowDefinition/>
                                                        <RowDefinition/>
                                                        <RowDefinition/>
                                                    </Grid.RowDefinitions>
                                                    <Grid.ColumnDefinitions>
                                                        <ColumnDefinition/>
                                                        <ColumnDefinition/>
                                                        <ColumnDefinition/>
                                                        <ColumnDefinition/>
                                                    </Grid.ColumnDefinitions>
                                                    <TextBlock Text="{Binding Id}" Grid.Row="0" Grid.Column="0"/>
                                                    <TextBlock Text="{Binding Name}" Grid.Row="0" Grid.Column="1"/>
                                                    <TextBlock Text="{Binding Author}" Grid.Row="0" Grid.Column="2"/>
                                                    <TextBlock Text="{Binding Comment}" Grid.Row="0" Grid.Column="3"/>
                                                    <TextBlock Text="{Binding Content}" Grid.Row="1" Grid.Column="0"/>
                                                    <TextBlock Text="{Binding CategoryName}" Grid.Row="1" Grid.Column="1"/>
                                                    <TextBlock Text="{Binding Summary}" Grid.Row="1" Grid.Column="2"/>
                                                    <TextBlock Text="{Binding Title}" Grid.Row="1" Grid.Column="3"/>
                                                    <TextBlock Text="{Binding Topic}" Grid.Row="2" Grid.Column="0"/>
                                                    <TextBlock Text="{Binding ISBN}" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"/>
                                                </Grid>
                                            </DataTemplate>
                                        </ItemsControl.ItemTemplate>
                                        <ItemsControl.Template>
                                            <ControlTemplate>
                                                <ScrollViewer CanContentScroll="True">
                                                    <ItemsPresenter/>
                                                </ScrollViewer>
                                            </ControlTemplate>
                                        </ItemsControl.Template>
                                    </ItemsControl>
                                </Border>

                            </Grid>
                        </Border>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>


//D:\C\WpfApp15\ClassfiedItemsControl.cs
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;
using WpfApp15.Models;

namespace WpfApp15
{
    /// <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:WpfApp15"
    ///
    ///
    /// 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:WpfApp15;assembly=WpfApp15"
    ///
    /// 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:ClassfiedItemsControl/>
    ///
    /// </summary>
    public class ClassfiedItemsControl : Control
    {
        static ClassfiedItemsControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ClassfiedItemsControl), new FrameworkPropertyMetadata(typeof(ClassfiedItemsControl)));
        }



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

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




        public string SelectedCategory
        {
            get { return (string)GetValue(SelectedCategoryProperty); }
            set { SetValue(SelectedCategoryProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SelectedCategory.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedCategoryProperty =
            DependencyProperty.Register(nameof(SelectedCategory), 
                typeof(string), 
                typeof(ClassfiedItemsControl), 
                new PropertyMetadata(string.Empty));







        public ObservableCollection<BookModel> BksCollection
        {
            get { return (ObservableCollection<BookModel>)GetValue(BksCollectionProperty); }
            set { SetValue(BksCollectionProperty, value); }
        }

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




    }
}


//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>
        <local:ClassfiedItemsControl CategoryList="{Binding CategoryList}"
                                     SelectedCategory="{Binding SelectedCategory,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                     BksCollection="{Binding BksCollection}"/>
    </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;
using WpfApp15.Models;

namespace WpfApp15
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class MainVM : INotifyPropertyChanged
    {
        static string url = "http://172.17.3.36:5000/api/books/getbooks/1000000";
        static HttpClient client = new HttpClient()
        {
            Timeout = TimeSpan.FromMinutes(1)
        };

        List<BookModel> allBks = new List<BookModel>();

        public MainVM()
        {
            if(!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
            {
                _ = InitBksCollectionAsync();
            }
        }

        private async Task InitBksCollectionAsync()
        {
            try
            {
                string jsonStr = await client.GetStringAsync(url);
                if(!string.IsNullOrWhiteSpace(jsonStr))
                {
                    allBks = JsonConvert.DeserializeObject<List<BookModel>>(jsonStr)?.ToList();
                    CategoryList = new ObservableCollection<string>(allBks.Select(x => x.CategoryName).Distinct());
                    SelectedCategory = CategoryList.FirstOrDefault();                    
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex?.Message);
            }
        }

        private ObservableCollection<BookModel> bksCollection;
        public ObservableCollection<BookModel> BksCollection
        {
            get
            {
                return bksCollection;
            }
            set
            {
                if(value!=bksCollection)
                {
                    bksCollection = value;
                    OnPropertyChanged();
                }
            }
        }

        private string selectedCategory;
        public string SelectedCategory
        {
            get
            {
                return selectedCategory;
            }
            set
            {
                if(value!=selectedCategory)
                {
                    selectedCategory = value;
                    OnPropertyChanged();
                    OnSelectedCategoryChanged();
                }
            }
        }

        private void OnSelectedCategoryChanged()
        {
            if(!string.IsNullOrWhiteSpace(SelectedCategory) && allBks!=null && allBks.Any())
            {
                BksCollection=new ObservableCollection<BookModel>(allBks.Where(x=>x.CategoryName==SelectedCategory).ToList());
                MainTitle = $"Selected category:{SelectedCategory}";
            }
        }


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

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

        public event PropertyChangedEventHandler? PropertyChanged;

        private void OnPropertyChanged([CallerMemberName]string propName="")
        {
            var handler = Volatile.Read(ref PropertyChanged);
            if(handler!=null)
            {
                handler(this, new PropertyChangedEventArgs(propName));
            }
        }
    }
}

 

 

 

 

image

 

 

 

 

 

 

image

 

 

 

 

 

 

image

 

image

 

posted @ 2026-10-03 14:44  FredGrit  阅读(3)  评论(0)    收藏  举报