WPF custom control TemplateBinding

//D:\C\WpfApp3\Models\Book.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace WpfApp3.Models
{
    public class Book
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public string Author { get; set; }
        public string ISBN { 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 CategoryName { get; set; }
    }
}


//D:\C\WpfApp3\Models\DelegateCommand.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Input;

namespace WpfApp3.Models
{
    public class DelegateCommand : ICommand
    {
        private readonly Action<object?> execute;
        private readonly Func<object?, bool>? canExecute;
        public DelegateCommand(Action<object?> executeValue, Func<object?, bool>? canExecuteValue = null)
        {
            execute = executeValue;
            canExecute = canExecuteValue;
        }

        public event EventHandler? CanExecuteChanged;

        public bool CanExecute(object? parameter)
        {
            return canExecute == null ? true : canExecute(parameter);
        }

        public void Execute(object? parameter)
        {
            execute(parameter);
        }

        public void RaiseCanExecuteChanged()
        {
            var handler = Volatile.Read(ref CanExecuteChanged);
            if(handler!=null)
            {
                var dispatcher = Application.Current.Dispatcher;
                if(dispatcher!=null)
                {
                    dispatcher.Invoke(() =>
                    {
                        handler(this, EventArgs.Empty);
                    });
                }
            }
        }
    }
}



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


    <Style TargetType="{x:Type local:DGControlcs}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:DGControlcs}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.Resources>
                                <Style TargetType="Button">
                                    <Setter Property="FontSize" Value="30"/>
                                    <Setter Property="Width" Value="200"/>
                                    <Setter Property="Margin" Value="5,0"/>
                                </Style>
                            </Grid.Resources>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,5">
                                <Button Content="Load Data"
                                        Command="{TemplateBinding LoadDataCommand}"/>
                                <Button Content="Export Data"
                                        Command="{TemplateBinding ExportAsJsonCommand}"/>
                                <Button Content="Clear Data"
                                        Command="{TemplateBinding ClearDataCommand}"/>
                            </StackPanel>

                            <DataGrid Grid.Row="1"
                                      ItemsSource="{Binding BksCollection}"
                                      VirtualizingPanel.IsVirtualizing="True"
                                      VirtualizingPanel.VirtualizationMode="Recycling"
                                      VirtualizingPanel.CacheLength="5,5"
                                      VirtualizingPanel.CacheLengthUnit="Item"
                                      ScrollViewer.CanContentScroll="True"
                                      ScrollViewer.IsDeferredScrollingEnabled="True"
                                      UseLayoutRounding="True"
                                      AutoGenerateColumns="True"
                                      IsReadOnly="True"
                                      CanUserAddRows="False"
                                      FontSize="30"
                                      CanUserReorderColumns="False"
                                      HeadersVisibility="Column">                                
                            </DataGrid>  
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>


//D:\C\WpfApp3\DGControlcs.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 WpfApp3.Models;

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



        public ICommand LoadDataCommand
        {
            get { return (ICommand)GetValue(LoadDataCommandProperty); }
            set { SetValue(LoadDataCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LoadDataCommand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LoadDataCommandProperty =
            DependencyProperty.Register(nameof(LoadDataCommand), 
                typeof(ICommand), 
                typeof(DGControlcs), 
                new PropertyMetadata(null));




        public ICommand ExportAsJsonCommand
        {
            get { return (ICommand)GetValue(ExportAsJsonCommandProperty); }
            set { SetValue(ExportAsJsonCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ExportAsJsonCommmand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ExportAsJsonCommandProperty =
            DependencyProperty.Register(nameof(ExportAsJsonCommand), 
                typeof(ICommand), 
                typeof(DGControlcs), 
                new PropertyMetadata(null));




        public ICommand ClearDataCommand
        {
            get { return (ICommand)GetValue(ClearDataCommandProperty); }
            set { SetValue(ClearDataCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ClearDataCommand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ClearDataCommandProperty =
            DependencyProperty.Register(nameof(ClearDataCommand), 
                typeof(ICommand), 
                typeof(DGControlcs), 
                new PropertyMetadata(null));







        public ObservableCollection<Book> BksCollection
        {
            get { return (ObservableCollection<Book>)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<Book>), 
                typeof(DGControlcs), 
                new PropertyMetadata(null));




    }
}


//D:\C\WpfApp3\MainWindow.xaml
<Window x:Class="WpfApp3.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:WpfApp3"
        mc:Ignorable="d"
        Title="{Binding MainTitle}"
        WindowState="Maximized">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Window.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="FontSize" Value="30"/>
        </Style>
        
    </Window.Resources>
    <Grid>
        <local:DGControlcs
                BksCollection="{Binding BksCollection}"
                LoadDataCommand="{Binding LoadDataCommand}"
                ExportAsJsonCommand="{Binding ExportCommand}"
                ClearDataCommand="{Binding ClearCommand}"/>
    </Grid>
</Window>


//D:\C\WpfApp3\MainWindow.xaml.cs
using Microsoft.Win32;
using Newtonsoft.Json;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
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 WpfApp3.Models;

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

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

        static bool isOperating = false;
        public MainVM()
        {
            
        }

        private ICommand loadDataCommand;
        public ICommand LoadDataCommand
        {
            get
            {
                if(loadDataCommand==null)
                {
                    loadDataCommand = new DelegateCommand(s =>
                    {
                        _ = LoadDataCommandExecuted(s);
                    });
                }
                return loadDataCommand;
            }
        }

        private ICommand exportCommand;
        public ICommand ExportCommand
        {
            get
            {
                if(exportCommand==null)
                {
                    exportCommand = new DelegateCommand(s =>
                    {
                        bool flowControl = ExportData();
                        if (!flowControl)
                        {
                            return;
                        }
                    });
                }
                return exportCommand;
            }
        }

        private bool ExportData()
        {
            try
            {
                if (isOperating)
                {
                    return false;
                }
                isOperating = true;
                string jsonStr = JsonConvert.SerializeObject(BksCollection, Formatting.Indented);
                if (!string.IsNullOrWhiteSpace(jsonStr))
                {
                    SaveFileDialog dlg = new SaveFileDialog();
                    dlg.Filter = "Json Files|*.json| All Files|*.*";
                    dlg.FileName = $"ExportedJson_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}.json";
                    if (dlg.ShowDialog() == true)
                    {
                        using (StreamWriter streamWriter = new StreamWriter(dlg.FileName, false, Encoding.UTF8))
                        {
                            streamWriter.WriteLine(jsonStr);
                            MessageBox.Show($"Write in {dlg.FileName}");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex?.Message);
            }
            finally
            {
                isOperating = false;
            }

            return true;
        }

        private async Task LoadDataCommandExecuted(object? obj)
        {
            if(isOperating)
            {
                return;
            }
            isOperating = true;
            try
            {
                string jsonStr = await client.GetStringAsync(url);
                var bks = JsonConvert.DeserializeObject<List<Book>>(jsonStr);
                if (bks != null && bks.Any())
                {
                    BksCollection = new ObservableCollection<Book>(bks);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex?.Message);
            }
            finally
            {
                isOperating = false;
            }           
        }

        private ICommand clearCommand;
        public ICommand ClearCommand
        {
            get
            {
                if(clearCommand == null)
                {
                    clearCommand = new DelegateCommand(ClearCommandExecuted);
                }
                return clearCommand;
            }
        }

        private void ClearCommandExecuted(object? obj)
        {
            BksCollection?.Clear();
        }

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

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

 

 

 

 

 

 

 

 

image

 

 

 

image

 

 

 

 

 

image

 

posted @ 2026-09-26 20:28  FredGrit  阅读(4)  评论(0)    收藏  举报