WPF ItemsControl ItemsPanelTemplate Canvas ItemTemplate DataTemplate

//xaml

<Window x:Class="WpfApp182.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:WpfApp182"
        mc:Ignorable="d"
        KeyDown="Window_KeyDown"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Path x:Name="triPath" Fill="Red">
            <Path.Data>
                <PathGeometry>
                    <PathFigure StartPoint="0,0" IsClosed="True">
                        <LineSegment Point="20,0"/>
                        <LineSegment Point="10,50"/>
                    </PathFigure>
                </PathGeometry>
            </Path.Data>
            <Path.RenderTransform>
                <TransformGroup>
                    <TranslateTransform x:Name="translater"
                                        X="{Binding TX,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                        Y="{Binding TY,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                    <RotateTransform x:Name="rotater"
                                     CenterX="{Binding TCenterX,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                     CenterY="{Binding TCenterY,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                </TransformGroup>
            </Path.RenderTransform>
        </Path>


        <Ellipse Width="{Binding ElpRadius,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 Height="{Binding ElpRadius,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 Stroke="Blue"
                 StrokeThickness="5"
                 VerticalAlignment="Center"
                 HorizontalAlignment="Center"
                 Panel.ZIndex="-1"/>

        <ItemsControl x:Name="ticksItemsControl">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Line X1="{Binding Line1StartX}"
                          Y1="{Binding Line1StartY}"
                          X2="{Binding Line1EndX}"
                          Y2="{Binding Line1EndY}"
                          Stroke="{Binding Line1Stroke}"
                          StrokeThickness="{Binding Line1StrokeThickness}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

        <ItemsControl x:Name="numbersItemsControl">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding NumStr}"
                               x:Name="numTbk"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Center"
                               Width="Auto"
                               Foreground="Black"
                               FontSize="30"
                               FontWeight="Bold">
                        <TextBlock.RenderTransform>
                            <TranslateTransform X="{Binding NumX}"
                                                Y="{Binding NumY}"/>
                        </TextBlock.RenderTransform>
                    </TextBlock>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>


//xaml.cs


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
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 WpfApp182
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            this.Loaded += MainWindow_Loaded;
            this.SizeChanged += MainWindow_SizeChanged;
        }

        private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Init();
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            Init();
        }

        private double tCenterX;
        public double TCenterX
        {
            get
            {
                return tCenterX;
            }
            set
            {
                if (value != tCenterX)
                {
                    tCenterX = value;
                    OnPropertyChanged(nameof(TCenterX));
                }
            }
        }

        private double tCenterY;
        public double TCenterY
        {
            get
            {
                return tCenterY;
            }
            set
            {
                if (value != tCenterY)
                {
                    tCenterY = value;
                    OnPropertyChanged(nameof(TCenterY));
                }
            }
        }

        private double tX;
        public double TX
        {
            get
            {
                return tX;
            }
            set
            {
                if (value != tX)
                {
                    tX = value;
                    OnPropertyChanged(nameof(TX));
                }
            }
        }

        private double tY;
        public double TY
        {
            get
            {
                return tY;
            }
            set
            {
                if (value != tY)
                {
                    tY = value;
                    OnPropertyChanged(nameof(TY));
                }
            }
        }

        private Point elpCenter;
        public Point ElpCenter
        {
            get
            {
                return elpCenter;
            }
            set
            {
                if (value != elpCenter)
                {
                    elpCenter = value;
                    OnPropertyChanged(nameof(ElpCenter));
                }
            }
        }

        private double elpRadius;
        public double ElpRadius
        {
            get
            {
                return elpRadius;
            }
            set
            {
                if (value != elpRadius)
                {
                    elpRadius = value;
                    OnPropertyChanged(nameof(ElpRadius));
                }
            }
        }

        private double line1Radius;
        public double Line1Radius
        {
            get
            {
                return line1Radius;
            }
            set
            {
                if (value != line1Radius)
                {
                    line1Radius = value;
                    OnPropertyChanged(nameof(Line1Radius));
                }
            }
        }

        private double numRadius;
        public double NumRadius
        {
            get
            {
                return numRadius;
            }
            set
            {
                if (value != numRadius)
                {
                    numRadius = value;
                    OnPropertyChanged(nameof(NumRadius));
                }
            }
        }

        private bool isPaused = false;
        private double shortTickLength = 30;
        private double longTickLength = 60;

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

        private System.Timers.Timer tmr { get; set; }

        private void Init()
        {
            var fe = this.Content as FrameworkElement;
            if (fe != null)
            {
                TCenterX = fe.ActualWidth / 2;
                TCenterY = fe.ActualHeight / 2;
                TX = fe.ActualWidth / 2 - 15;
                TY = 0;
                ElpCenter = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2);
                ElpRadius = fe.ActualHeight - 50;
                Line1Radius = fe.ActualHeight / 2 - 25;
                NumRadius = fe.ActualHeight / 2 - 80;
            }

            InitTicks();

            InitNumbers();

            if (tmr != null)
            {
                return;
            }

            tmr = new System.Timers.Timer();
            tmr.Interval = 1000;
            tmr.Elapsed += Tmr_Elapsed;
            tmr.Start();
        }

        private void InitNumbers()
        {
            var numTbk = this.FindName("numTbk") as TextBlock;
            List<NumClass> numsList = new List<NumClass>();
            double angleStep = 360 / 12;

            for (int i = 1; i <= 12; i++)
            {
                double angleRadian = (angleStep * (i) - 90) * Math.PI / 180;
                numsList.Add(new NumClass()
                {
                    NumStr = i.ToString(),
                    NumX = TCenterX + NumRadius * Math.Cos(angleRadian)-15,
                    NumY = tCenterY + NumRadius * Math.Sin(angleRadian)-25
                });
            }
            numbersItemsControl.ItemsSource = numsList;
        }

        private void InitTicks()
        {
            int ticksCount = 60;
            double angleStep = 360 / 60;
            List<Line1Tick> linesList = new List<Line1Tick>();

            for (int i = 0; i < ticksCount; i++)
            {
                double angleRadian = (i * angleStep - 90) * Math.PI / 180;
                double tickLength = i % 5 == 0 ? longTickLength : shortTickLength;
                Brush lineStroke = i % 5 == 0 ? Brushes.Red : Brushes.Black;
                double lineThickness = i % 5 == 0 ? 5 : 2;
                linesList.Add(new Line1Tick()
                {
                    Line1StartX = TCenterX + Line1Radius * Math.Cos(angleRadian),
                    Line1StartY = TCenterY + Line1Radius * Math.Sin(angleRadian),
                    Line1EndX = TCenterX + (Line1Radius - tickLength) * Math.Cos(angleRadian),
                    Line1EndY = TCenterY + (Line1Radius - tickLength) * Math.Sin(angleRadian),
                    Line1Stroke = lineStroke,
                    Line1StrokeThickness = lineThickness
                });
            }
            ticksItemsControl.ItemsSource = linesList;
        }

        private void Tmr_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (isPaused)
            {
                return;
            }
            try
            {
                Application.Current?.Dispatcher.BeginInvoke(new Action(() =>
                {
                    rotater.Angle += 10;
                    if (rotater.Angle >= 360)
                    {
                        rotater.Angle = 0;
                    }
                    this.Title = rotater.Angle.ToString();
                    Console.WriteLine(Mouse.GetPosition(triPath).X + "," + Mouse.GetPosition(triPath).Y);
                }));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + "\n" + ex.StackTrace.ToString());
            }
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            isPaused = !isPaused;
        }

    }

    public class Line1Tick
    {
        public double Line1StartX { get; set; }
        public double Line1StartY { get; set; }
        public double Line1EndX { get; set; }
        public double Line1EndY { get; set; }
        public Brush Line1Stroke { get; set; }
        public double Line1StrokeThickness { get; set; }
    }


    public class NumClass
    {
        public string NumStr { get; set; }
        public double NumX { get; set; }
        public double NumY { get; set; }
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2025-03-29 17:05  FredGrit  阅读(36)  评论(0)    收藏  举报