WPF Canvas在Image 圖像上繪圖,自適應縮放.

效果如圖

 

 

實現了繪圖,自適應縮放

核心代碼如下

    <Window.InputBindings>
        <KeyBinding Key="Z" Modifiers="Ctrl" Command="{Binding UndoCommand}" />
    </Window.InputBindings>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SizeChanged">
            <i:InvokeCommandAction Command="{Binding SizeChangedCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <Grid>
        <Grid  Background="AliceBlue">
            <Grid.RowDefinitions>
                <RowDefinition Height="40" />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.35*" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center"  Margin="10,0,0,0" Grid.ColumnSpan="2">
                <!--<Button Content="+" Command="{Binding DrawRectCommand}" />-->
                <Button Content=" + " Margin="10,0,0,0" Command="{Binding CreateCommand}" />
                <Button Content="Save" Margin="10,0,0,0" Command="{Binding SaveCommand}" />
                <Button Content="Clear" Margin="10,0,0,0" Command="{Binding ClearCommand}" />
                <Button Content="Cancel" Margin="10,0,0,0" Command="{Binding UndoCommand}" />
                <Button Content="Refresh" Margin="10,0,0,0" Command="{Binding RefreshCommand}" />
            </StackPanel>

            <StackPanel Grid.Row="1" Grid.Column="0">
                <ListBox  SelectedItem="{Binding SelectedSlide}">
                    <ListBox.Resources>
                        <CollectionViewSource x:Key="SlideControlParams" Source="{Binding SlideControlParams}" />
                    </ListBox.Resources>
                    <ListBox.ItemsSource>
                        <CompositeCollection>
                            <CollectionContainer Collection="{Binding Source={StaticResource SlideControlParams}}" />
                        </CompositeCollection>
                    </ListBox.ItemsSource>
              
                    <ListBox.ItemContainerStyle>
                        <Style TargetType="ListBoxItem">
                            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                        </Style>
                    </ListBox.ItemContainerStyle>

                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Grid  Height="40" VerticalAlignment="Center">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition />
                                    <ColumnDefinition Width="50" />
                                </Grid.ColumnDefinitions>

                                <Grid.InputBindings>
                                    <MouseBinding Command="{Binding DataContext.OnListViewItemDoubleClick, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"
                                                      MouseAction="LeftDoubleClick" CommandParameter="{Binding }" />
                                </Grid.InputBindings>
                                <TextBlock Text="{Binding Path= Name}">

                                    <TextBlock.VerticalAlignment>Center</TextBlock.VerticalAlignment>
                                    <TextBlock.Margin>5,0,0,0</TextBlock.Margin>
                                </TextBlock>
                                <TextBox Text="{Binding Name,Mode=TwoWay}" VerticalAlignment="Center" Margin="5,0,0,0" Visibility="{Binding EditStatus}" />

                                <Button Content="X" Grid.Column="1" Width="40"  VerticalAlignment="Center" Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" CommandParameter="{Binding }" />
                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </StackPanel>

            <Image Source="{Binding SelectedSlide.ImagePath}" Grid.Row="1" x:Name="imgSlide" Grid.Column="1">            
            </Image>

            <Canvas Grid.Row="1" Name="canvas" Background="#19DAB1B1" Grid.Column="1">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseLeftButtonDown">
                        <cmd:EventToCommand Command="{Binding CmdLeftMouseDown}"  PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseLeftButtonUp">
                        <cmd:EventToCommand Command="{Binding CmdLeftMouseUp}" PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseMove">
                        <cmd:EventToCommand Command="{Binding CmdLeftMouseMove}" PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseRightButtonUp">
                        <cmd:EventToCommand Command="{Binding MouseRightButtonUp}"  PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Canvas>
        </Grid>
    </Grid>
</Window>
    public class UCP16ConfigVM : ViewModelBase
    {
        public UCP16ConfigVM(Canvas _canvas, Image _imgSlide)
        {
            canvas = _canvas;
            imgSlide = _imgSlide;
            InitEnv();
            InitCommand();
            LoadConfig();
            string rootPath = System.Environment.CurrentDirectory;
            jsonPath = System.IO.Path.Combine(rootPath, "ScanPara", "slideParms.json");
            imgDir = System.IO.Path.Combine(rootPath, "ScanPara", "SlideConfigImages");
            if (!Directory.Exists(imgDir))
            {
                Directory.CreateDirectory(imgDir);
            }
            if (!File.Exists(jsonPath))
            {
                SlideP16Parms prams = new SlideP16Parms();
                var str = JsonConvert.SerializeObject(prams, Formatting.Indented);
                File.WriteAllText(jsonPath, str);
            }
        }

        #region private param

        /// <summary>
        /// 是否正在繪圖狀態
        /// </summary>
        private bool isDrawing = false;

        /// <summary>
        /// 起始點
        /// </summary>
        private Point startPoint;

        /// <summary>
        /// 結束點
        /// </summary>
        private Point endPoint;

        /// <summary>
        /// canvas控件
        /// </summary>
        private Canvas canvas = null;

        /// <summary>
        /// image控件
        /// </summary>
        private Image imgSlide = null;

        /// <summary>
        /// 顏色刷
        /// </summary>
        private Brush brushDanger;

        /// <summary>
        /// rect效果
        /// </summary>
        private DropShadowEffect shadowEffect;

        /// <summary>
        /// 臨時矩形
        /// </summary>
        private Rectangle tempRect = null;

        private readonly string jsonPath;
        private readonly string imgDir;

        //圖像控件相對於canva的座標
        private Point imgMarginPos;

        #endregion private param

        #region ViewModels

        private ObservableCollection<SlideP16ItemCombine> _SlideControlParams;

        /// <summary>
        /// 控件對應的座標
        /// </summary>
        public ObservableCollection<SlideP16ItemCombine> SlideControlParams
        {
            get => _SlideControlParams;
            set { Set(ref _SlideControlParams, value); }
        }

        ///// <summary>
        ///// 圖像座標,需要同步更新
        ///// </summary>
        //public List<SlideP16Item> SlideImageParams { get; set; }

        private SlideP16ItemCombine _SelectedSlide;

        public SlideP16ItemCombine SelectedSlide
        {
            get => _SelectedSlide;
            set
            {
                if (value != _SelectedSlide)
                {
                    Set(ref _SelectedSlide, value);
                    foreach (var item in SlideControlParams)
                    {
                        if (item != value)
                            item.EditStatus = Visibility.Collapsed;
                    }
                    LoadPoints();
                }
            }
        }

        #endregion ViewModels

        #region Command

        /// <summary>
        /// 清空所有繪圖
        /// </summary>
        public RelayCommand ClearCommand { get; private set; }

        /// <summary>
        /// 取消,撤銷上一步操作
        /// </summary>
        public RelayCommand UndoCommand { get; private set; }

        public RelayCommand<MouseEventArgs> CmdLeftMouseDown { get; private set; }
        public RelayCommand<MouseEventArgs> CmdLeftMouseMove { get; private set; }
        public RelayCommand<MouseEventArgs> CmdLeftMouseUp { get; private set; }
        public RelayCommand<MouseEventArgs> MouseRightButtonUp { get; private set; }

        public RelayCommand<SlideP16ItemCombine> OnListViewItemDoubleClick { get; private set; }

        /// <summary>
        /// 刷新數據
        /// </summary>
        public RelayCommand RefreshCommand { get; private set; }

        /// <summary>
        /// 保存
        /// </summary>
        public RelayCommand SaveCommand { get; set; }

        /// <summary>
        /// 新建配方
        /// </summary>
        public RelayCommand CreateCommand { get; set; }

        public RelayCommand<SlideP16ItemCombine> DeleteCommand { get; set; }

        public RelayCommand SizeChangedCommand { get; private set; }

        #endregion Command

        private static readonly string SOURCE_DEFAULT =
            @"pack://application:,,,/TestWPF;component/Resources/Images/upload.png";

        /// <summary>
        /// 初始化界面主題
        /// </summary>
        private void InitEnv()
        {
            string hexColor = "#F56C6C";
            BrushConverter converter = new BrushConverter();
            brushDanger = (Brush)converter.ConvertFromString(hexColor);
            shadowEffect = new DropShadowEffect
            {
                Color = Colors.White, // 陰影顏色
                Direction = 0, // 陰影方向
                BlurRadius = 3, // 模糊半徑
                Opacity = 0.6, // 陰影不透明度
                ShadowDepth = 0
            };
        }

        /// <summary>
        /// 初始化綁定命令
        /// </summary>
        private void InitCommand()
        {
            CmdLeftMouseDown = new RelayCommand<MouseEventArgs>(LeftMouseDown);
            CmdLeftMouseMove = new RelayCommand<MouseEventArgs>(LeftMouseMove);
            CmdLeftMouseUp = new RelayCommand<MouseEventArgs>(LeftMouseUp);
            MouseRightButtonUp = new RelayCommand<MouseEventArgs>(RightMouseUp);
            ClearCommand = new RelayCommand(() =>
            {
                ClearRectangle();
            });
            UndoCommand = new RelayCommand(() =>
            {
                if (canvas.Children.Count > 0)
                {
                    if (canvas.Children[canvas.Children.Count - 1] is Rectangle rect)
                    {
                        RemoveRectangle(rect);
                    }
                    // canvas.Children.RemoveAt(canvas.Children.Count - 1);
                }
            });
            SaveCommand = new RelayCommand(() =>
            {
                SaveResult();
            });
            CreateCommand = new RelayCommand(() =>
            {
                CreateNewItem(SOURCE_DEFAULT);
            });

            DeleteCommand = new RelayCommand<SlideP16ItemCombine>(
                (SlideP16ItemCombine param) =>
                {
                    SlideControlParams.Remove(param);
                    return;
                }
            );
            OnListViewItemDoubleClick = new RelayCommand<SlideP16ItemCombine>(
                (args) =>
                {
                    args.EditStatus = Visibility.Visible;
                }
            );
            RefreshCommand = new RelayCommand(RefreshData);
            SizeChangedCommand = new RelayCommand(Control_SizeChanged);
        }

        #region Command對應方法

        /// <summary>
        /// 左鍵按下事件
        /// </summary>
        /// <param name="e"></param>
        private void LeftMouseDown(MouseEventArgs e)
        {
            if (SelectedSlide == null)
                return;
            if (SelectedSlide.ImagePath == SOURCE_DEFAULT)
            {
                LoadLocalImage();
                return;
            }
            isDrawing = true;

            if (e.OriginalSource is Canvas)
            {
                startPoint = e.GetPosition((IInputElement)e.Source);
            }
            else
            {
                startPoint = (e.Source as Rectangle).TranslatePoint(
                    e.GetPosition((IInputElement)e.Source),
                    canvas
                );
            }
            //   startPoint = e.GetPosition((IInputElement)e.Source);
            tempRect = CreateTempRect();
            Trace.WriteLine("down");
            canvas.Children.Add(tempRect);
        }

        private void RightMouseUp(MouseEventArgs e)
        {
            if (SelectedSlide == null)
                return;
            if (e.OriginalSource is Rectangle)
            {
                var rect = e.OriginalSource as Rectangle;
                RemoveRectangle(rect);
            }
        }

        private void LeftMouseUp(MouseEventArgs e)
        {
            if (SelectedSlide == null)
                return;
            isDrawing = false;
            AddRectangle();
            tempRect = null;
        }

        private void LeftMouseMove(MouseEventArgs e)
        {
            if (SelectedSlide == null)
                return;
            if (!isDrawing)
                return;
            if (e.OriginalSource is Canvas)
            {
                endPoint = e.GetPosition((IInputElement)e.Source);
            }
            else
            {
                endPoint = (e.Source as Rectangle).TranslatePoint(
                    e.GetPosition((IInputElement)e.Source),
                    canvas
                );
            }
            UpdateRectangle();
        }

        #endregion Command對應方法

        #region other func

        private Rectangle CreateTempRect()
        {
            Rectangle rect = new Rectangle
            {
                Width = 0,
                Height = 0,
                Stroke = brushDanger, // Brushes.Black,
                StrokeThickness = 2,
                Fill = Brushes.Transparent,
                IsHitTestVisible = true
            };

            rect.Effect = shadowEffect;
            Canvas.SetLeft(rect, startPoint.X);
            Canvas.SetTop(rect, startPoint.Y);

            return rect;
        }

        /// <summary>
        /// 刷新rect軌跡,並不會添加到數組
        /// </summary>
        private void UpdateRectangle()
        {
            AddRectangle(true);
            return;
        }

        private void AddRectangle(bool isUpdate = false)
        {
            try
            {
                double width = (endPoint.X - startPoint.X);
                double height = endPoint.Y - startPoint.Y;
                double left = startPoint.X;
                double top = startPoint.Y;
                if (width < 0)
                {
                    left = endPoint.X;
                    width = -width;
                }
                if (height < 0)
                {
                    top = endPoint.Y;
                    height = -height;
                }
                tempRect.Width = width;
                tempRect.Height = height;

                Canvas.SetLeft(tempRect, left);
                Canvas.SetTop(tempRect, top);

                if (!isUpdate) //如果完成,則添加到列表
                {
                    var tempPoint = new SlideP16ItemPoint
                    {
                        Height = height,
                        Width = width,
                        X = left,
                        Y = top,
                        IsImagePoint = false,
                    };
                    SelectedSlide.ItemPoints.Add(tempPoint);
                    AddControlPoint(SelectedSlide.ItemPoints[SelectedSlide.ItemPoints.Count - 1]);
                }
            }
            catch (Exception ex)
            {
                return;
            }
        }

        /// <summary>
        /// 刪除界面指定rectangle對象,並從綁定的隊列移除
        /// </summary>
        /// <param name="rect"></param>
        private void RemoveRectangle(Rectangle rect)
        {
            var imagePoint = ConvertToImageCoordinates(
                new SlideP16ItemPoint
                {
                    X = Canvas.GetLeft(rect),
                    Y = Canvas.GetTop(rect),
                    Width = rect.Width,
                    Height = rect.Height
                }
            );

            var toDeletePoint = this
                .SelectedSlide.ItemPoints.Where(x =>
                    x.IsImagePoint
                    && Math.Abs(x.Width - imagePoint.Width) <= 0.1
                    && Math.Abs(x.Height - imagePoint.Height) <= 0.1
                    && Math.Abs(x.X - imagePoint.X) <= 0.1
                    && Math.Abs(x.Y - imagePoint.Y) <= 0.1
                )
                .FirstOrDefault();
            if (toDeletePoint != null)
                SelectedSlide.ItemPoints.Remove(toDeletePoint);
            canvas.Children.Remove(rect);
        }

        /// <summary>
        /// 刪除所有繪圖
        /// </summary>
        private void ClearRectangle()
        {
            canvas.Children.Clear();
            this.SelectedSlide.ItemPoints.Clear();
        }


        /// <summary>
        /// 控件座標轉換爲圖像座標
        /// </summary>
        /// <param name="pointControl"></param>
        /// <returns></returns>
        private SlideP16ItemPoint ConvertToImageCoordinates(SlideP16ItemPoint pointControl)
        {
            double scaleX =
                imgSlide.ActualWidth
                / (imgSlide.Source == null ? imgSlide.ActualWidth : imgSlide.Source.Width);
            double scaleY =
                imgSlide.ActualHeight
                / (imgSlide.Source == null ? imgSlide.ActualHeight : imgSlide.Source.Height);
            ;
            double imageRectX = pointControl.X / scaleX;
            double imageRectY = pointControl.Y / scaleY;
            double imageRectWidth = pointControl.Width / scaleX;
            double imageRectHeight = pointControl.Height / scaleY;
            return new SlideP16ItemPoint
            {
                Height = imageRectHeight,
                Width = imageRectWidth,
                X = imageRectX,
                Y = imageRectY,
            };
        }

        //private double scaleX;
        //private double scaleY;
        /// <summary>
        /// 圖像座標轉控件座標
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        private SlideP16ItemPoint ConvertToControlCoordinates(SlideP16ItemPoint point)
        {
            var scaleX = imgSlide.ActualWidth / imgSlide.Source.Width;
            var scaleY = imgSlide.ActualHeight / imgSlide.Source.Height;
            // 根據縮放比例計算控件上的位置和尺寸
            double controlX = point.X * scaleX;
            double controlY = point.Y * scaleY;
            double controlWidth = point.Width * scaleX;
            double controlHeight = point.Height * scaleY;
            return new SlideP16ItemPoint
            {
                Height = controlHeight,
                Width = controlWidth,
                X = controlX,
                Y = controlY,
            };
        }

        private void LoadConfig()
        {
            string jsonPath = System.Environment.CurrentDirectory;
            jsonPath = System.IO.Path.Combine(jsonPath, "ScanPara", "slideParms.json");
            var json = File.ReadAllText(jsonPath);
            SlideP16Parms rt = JsonConvert.DeserializeObject<SlideP16Parms>(json);
            IEnumerable<SlideP16ItemCombine> items = rt.Items.Select(x => new SlideP16ItemCombine
            {
                EditStatus = Visibility.Collapsed,
                ID = x.ID,
                ImagePath = x.ImagePath,
                ItemPoints = x.ItemPoints,
                Name = x.Name
            });
            SlideControlParams = new ObservableCollection<SlideP16ItemCombine>(items);
        }

        /// <summary>
        /// 加載point座標,並繪製到ui
        /// </summary>
        /// <param name="isControl"></param>
        private void LoadPoints()
        {
            imgSlide.Dispatcher.Invoke(
                new Action(() =>
                {
                    if (this.SelectedSlide == null)
                        return;
                    imgMarginPos = imgSlide.TranslatePoint(new Point(0, 0), canvas);
                    canvas.Children.Clear();
                    foreach (SlideP16ItemPoint p in SelectedSlide.ItemPoints)
                    {
                        SlideP16ItemPoint t_point = null;

                        if (p.IsImagePoint)
                            t_point = ConvertToControlCoordinates(p);
                        else
                            t_point = p;

                        Rectangle tempRect = new Rectangle
                        {
                            Width = t_point.Width,
                            Height = t_point.Height,
                            Stroke = brushDanger, // Brushes.Black,
                            StrokeThickness = 2,
                            Fill = Brushes.Transparent,
                            IsHitTestVisible = true
                        };

                        tempRect.Effect = shadowEffect;
                        Canvas.SetLeft(tempRect, t_point.X);
                        Canvas.SetTop(tempRect, t_point.Y);
                        //  Trace.WriteLine($"tempRect x:{t_point.X} y:{t_point.Y},width:{tempRect.Width},height:{tempRect.Height}");
                        canvas.Children.Add(tempRect);
                    }
                    //   Trace.WriteLine("cavnas.children.count:" + canvas.Children.Count);
                }),
                DispatcherPriority.Loaded
            );
        }

        private void AddControlPoint(SlideP16ItemPoint t_point)
        {
            Rectangle tempRect = new Rectangle
            {
                Width = t_point.Width,
                Height = t_point.Height,
                Stroke = brushDanger, // Brushes.Black,
                StrokeThickness = 2,
                Fill = Brushes.Transparent,
                IsHitTestVisible = true
            };

            tempRect.Effect = shadowEffect;
            Canvas.SetLeft(tempRect, t_point.X);
            Canvas.SetTop(tempRect, t_point.Y);
            //      canvas.Children.Add(tempRect);
            Trace.WriteLine("cavnas.children.count:" + canvas.Children.Count);
        }

        private void CreateNewItem(string imgPath)
        {
            int id = 0;
            if (this.SlideControlParams?.Count > 0)
                id = this.SlideControlParams.Max(x => x.ID) + 1;
            var item = new SlideP16ItemCombine()
            {
                ID = id,
                ImagePath = imgPath,
                Name = id.ToString(),
                ItemPoints = new List<SlideP16ItemPoint>() { },
                EditStatus = Visibility.Visible
            };

            this.SlideControlParams.Add(item);
            //this.SlideImageParams.Add(item);
            this.SelectedSlide = item;
        }

        private void LoadLocalImage()
        {
            // 創建 OpenFileDialog 對象
            OpenFileDialog openFileDialog = new OpenFileDialog();
            // 設置文件類型過濾器,只允許選擇圖片文件
            openFileDialog.Filter =
                "Image files (*.jpg;*.jpeg;*.bmp;*.png)|*.jpg;*.jpeg;*.bmp;*.png|All files (*.*)|*.*";
            // 設置默認文件類型篩選器
            openFileDialog.FilterIndex = 1;
            // 是否允許多選
            openFileDialog.Multiselect = false;
            // 顯示對話框並獲取用戶的操作結果
            bool? result = openFileDialog.ShowDialog();
            // 如果用戶點擊了確認按鈕
            if (result == true)
            {
                try
                {
                    // 獲取選擇的文件名
                    string fileName = openFileDialog.FileName;
                    FileInfo fn = new FileInfo(fileName);
                    string targeImgPath = System.IO.Path.Combine(
                        imgDir,
                        "P16_" + SelectedSlide.ID.ToString() + fn.Extension
                    );
                    File.Copy(fileName, targeImgPath, true);
                    // 將 BitmapImage 對象設置爲界面上的 Image 控件的 Source
                    SelectedSlide.ImagePath = targeImgPath; // bitmapImage;
                }
                catch (Exception ex)
                {
                    // 處理異常情況
                    HandyControl.Controls.MessageBox.Show(
                        $"Error loading image: {ex.Message}",
                        "Error",
                        MessageBoxButton.OK,
                        MessageBoxImage.Error
                    );
                }
            }
        }

        /// <summary>
        /// 保存結果到json
        /// </summary>
        private void SaveResult()
        {
            SlideP16Parms prams = new SlideP16Parms();
            prams.Items = this.SlideControlParams.Select(x => (SlideP16Item)x).ToList();
            foreach (var p in prams.Items)
            {
                for (int i = 0; i < p.ItemPoints.Count; i++)
                {
                    if (!p.ItemPoints[i].IsImagePoint)
                        p.ItemPoints[i] = ConvertToImageCoordinates(p.ItemPoints[i]); // ConvertToImageCoordinates();
                }
            }
            var str = JsonConvert.SerializeObject(prams, Formatting.Indented); // JsonConvert.SerializeObject(prams, Formatting.Indented);
            File.WriteAllText(jsonPath, str);
        }

        /// <summary>
        /// 刷新頁面數據,重新讀取
        /// </summary>
        private void RefreshData()
        {
            LoadConfig();
        }

        private void Control_SizeChanged()
        {
            if (imgSlide.Source == null || canvas.Children.Count == 0)
                return;
            var scaleX = imgSlide.ActualWidth / imgSlide.Source.Width;
            var scaleY = imgSlide.ActualHeight / imgSlide.Source.Height;
            imgMarginPos = imgSlide.TranslatePoint(new Point(0, 0), canvas); //將Image控件的(0,0)座標點轉換爲相對於canvas的座標點。返回的Point對象就表示了Image控件在canvas中的偏移量。
            var offetX = imgMarginPos.X;
            var offetY = imgMarginPos.Y;
            for (int i = 0; i < canvas.Children.Count; i++)
            {
                var element = canvas.Children[i] as Rectangle;

                var tempRect = SelectedSlide.ItemPoints[i];
                //if (!tempRect.IsImagePoint)
                //{
                //    tempRect = ConvertToImageCoordinates(tempRect); //不可行,因爲此時轉換的時候,已經是size-changed之後了,無法正確轉換
                //}
                var cav = VisualTreeHelper.GetParent(imgSlide) as Canvas;

                double left = tempRect.X;
                double top = tempRect.Y;
                left = left * scaleX;
                top = top * scaleY;
                left += offetX;
                top += offetY;
                var width = tempRect.Width; // element.ActualWidth;
                var height = tempRect.Height; // element.ActualHeight;
                width *= scaleX;
                height *= scaleY;
                Trace.WriteLine("rq.scaleX:" + scaleX);
                Trace.WriteLine("rq.scaleY:" + scaleY);
                Trace.WriteLine("rq.element width:" + width);
                Trace.WriteLine("rq.element height:" + height);
                Canvas.SetLeft(element, left);
                Canvas.SetTop(element, top);
                element.Width = width;
                element.Height = height;
                Trace.WriteLine("rq.left:" + left);
                Trace.WriteLine("rq.top:" + top);
                Trace.WriteLine("rq.width:" + width);
                Trace.WriteLine("rq.height:" + height);
            }
        }

        #endregion other func
    }

    #region json映射類 P16玻片參數

    public class SlideP16ItemCombine : SlideP16Item
    {
        private Visibility _EditStatus;

        public Visibility EditStatus
        {
            get => _EditStatus;
            set => Set(ref _EditStatus, value);
        }
    }

    public class SlideP16Parms
    {
        public int ApplyID { get; set; }
        public List<SlideP16Item> Items { get; set; }
    }

    /// <summary>
    /// P16玻片配置信息
    /// </summary>
    public class SlideP16Item : ViewModelBase
    {
        public int ID { get; set; }
        public List<SlideP16ItemPoint> ItemPoints { get; set; }

        private string _Name;

        public string Name
        {
            get => _Name;
            set => Set(ref _Name, value);
        }

        private string _ImagePath;

        /// <summary>
        /// 圖片路徑
        /// </summary>
        public string ImagePath
        {
            get => _ImagePath;
            set => Set(ref _ImagePath, value);
        }
    }

    /// <summary>
    /// p16玻片子配置
    /// </summary>
    public class SlideP16ItemPoint
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Width { get; set; }
        public double Height { get; set; }

        /// <summary>
        /// 是否爲圖像座標,json讀寫忽略
        /// </summary>
        [JsonIgnore]
        public bool IsImagePoint { get; set; } = true;
    }

    #endregion json映射類
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章