WPF CustomControl override Template in Generic.xaml and invoke different style

 

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

    <Style TargetType="{x:Type local:DateTimePicker}"
           x:Key="DateTimePickerStyle1">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:DateTimePicker}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Width="500"
                            Height="500">
                        <StackPanel Orientation="Vertical">
                            <Calendar x:Name="PART_Calendar"
                                      SelectedDate="{Binding SelectedDate}">
                                <Calendar.LayoutTransform>
                                    <ScaleTransform ScaleX="1.5"
                                                    ScaleY="1.5"/>
                                </Calendar.LayoutTransform>
                            </Calendar>
                            <TextBlock x:Name="PART_DTTbk"
                                       Text="{Binding Path=SelectedDTStr,RelativeSource={RelativeSource AncestorType={x:Type local:DateTimePicker}}}"
                                       FontSize="20"
                                       HorizontalAlignment="Center"/>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="{x:Type local:DateTimePicker}"
           x:Key="DateTimePickerStyle2">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:DateTimePicker}">
                    <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                            Width="500"
                            Height="500">
                        <StackPanel Orientation="Vertical">
                            <TextBlock x:Name="PART_DTTbk"
                                       Text="{Binding Path=SelectedDTStr,RelativeSource={RelativeSource AncestorType={x:Type local:DateTimePicker}}}"
                                       FontSize="20"
                                       HorizontalAlignment="Center"/>

                            <Calendar x:Name="PART_Calendar"
                                  SelectedDate="{Binding SelectedDate}">
                                <Calendar.LayoutTransform>
                                    <ScaleTransform ScaleX="1.5"
                                                ScaleY="1.5"/>
                                </Calendar.LayoutTransform>
                            </Calendar>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


</ResourceDictionary>


//D:\C\WpfApp10\DateTimePicker.cs
using System;
using System.Collections.Generic;
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 WpfApp10
{
    /// <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:WpfApp10"
    ///
    ///
    /// 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:WpfApp10;assembly=WpfApp10"
    ///
    /// 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:DateTimePicker/>
    ///
    /// </summary>
    public class DateTimePicker : Control
    {
        private Calendar calendarDT;
        public Calendar CalendarDT
        {
            get
            {
                return calendarDT;
            }
            set
            {
                if (calendarDT != null)
                {
                    calendarDT.SelectedDatesChanged -= CalendarDT_SelectedDatesChanged;
                }

                calendarDT = value;
                if (calendarDT != null)
                {
                    calendarDT.SelectedDatesChanged += CalendarDT_SelectedDatesChanged;
                }
            }
        }

        private void CalendarDT_SelectedDatesChanged(object? sender, SelectionChangedEventArgs e)
        {
            var cal = sender as Calendar;
            if (cal != null)
            {
                SelectedDT = cal.SelectedDate;
                if (SelectedDT.HasValue)
                {
                    SelectedDTStr = SelectedDT.Value.ToString("yyyy-MM-dd: HH:mm:ss.ffff");
                }
            }
        }

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

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            var _calend = GetTemplateChild("PART_Calendar") as Calendar;
            if (_calend != null)
            {
                CalendarDT = _calend;
            }
        }

        public DateTime? SelectedDT
        {
            get { return (DateTime?)GetValue(SelectedDTProperty); }
            set { SetValue(SelectedDTProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SelctedDT.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedDTProperty =
            DependencyProperty.Register(nameof(SelectedDT),
                typeof(DateTime?),
                typeof(DateTimePicker),
                new PropertyMetadata(DateTime.Now, OnSelctedDTChanged));

        private static void OnSelctedDTChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var dtPicker = d as DateTimePicker;
            if (dtPicker != null)
            {
                if (dtPicker.SelectedDT.HasValue)
                {
                    dtPicker.SelectedDTStr = dtPicker.SelectedDT.Value.ToString("yyyy-MM-dd:HH:mm:ss.ffff");
                }
            }
        }

        public string SelectedDTStr
        {
            get { return (string)GetValue(SelectedDTStrProperty); }
            set { SetValue(SelectedDTStrProperty, value); }
        }

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



    }
}


//D:\C\WpfApp10\App.xaml
<Application x:Class="WpfApp10.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApp10"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Themes/Generic.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>


//D:\C\WpfApp10\MainWindow.xaml
<Window x:Class="WpfApp10.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:WpfApp10"
        mc:Ignorable="d"
        Title="{Binding MainTitle}" Height="450" Width="800">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <local:DateTimePicker
            Grid.Row="0"
            Grid.Column="0"
            Style="{StaticResource DateTimePickerStyle1}"
            SelectedDT="{Binding SelectedDT,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>

        <local:DateTimePicker 
            Grid.Row="0"
            Grid.Column="1"
            Style="{StaticResource DateTimePickerStyle2}"
            SelectedDT="{Binding SelectedDT2,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</Window>


//D:\C\WpfApp10\MainWindow.xaml.cs
using System.ComponentModel;
using System.Reflection.Metadata;
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 WpfApp10
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class MainVM : INotifyPropertyChanged
    {

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

        private DateTime? selectedDT2;
        public DateTime? SelectedDT2
        {
            get
            {
                return selectedDT2;
            }
            set
            {
                if (value != selectedDT2)
                {
                    selectedDT2 = value;
                    OnPropertyChanged();
                    if (SelectedDT2.HasValue)
                    {
                        MainTitle = $"DateTimePicker2,{SelectedDT2.Value.ToString("yyyy-MM-dd HH:mm:ss.ffff")}";
                    }
                }
            }
        }

        private DateTime? selectedDT;
        public DateTime? SelectedDT
        {
            get
            {
                return selectedDT;
            }
            set
            {
                if (value != selectedDT)
                {
                    selectedDT = value;
                    OnPropertyChanged();
                    if (SelectedDT.HasValue)
                    {
                        MainTitle = $"DateTimePicker1,{SelectedDT.Value.ToString("yyyy-MM-dd HH:mm:ss.ffff")}";
                    }
                }
            }
        }

        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

 

posted @ 2026-09-05 21:36  FredGrit  阅读(3)  评论(0)    收藏  举报