【问题标题】:how to get the visible area of canvas in wpf如何在wpf中获取画布的可见区域
【发布时间】:2023-03-25 10:50:01
【问题描述】:

我正在创建一个应用程序,就像在 WPF 中的绘画一样,我想向它添加缩放功能。我将画布作为父级,并将其上的可写位图作为我绘制的子级。当画布尺寸较小时,我在可写位图上绘制很流畅,但是当画布尺寸较大时,放大它,画布尺寸会很大,在这么大的区域上绘制会出现问题。所以我想找到画布的可见区域,这样我就可以顺利地在上面画画了。 请给我一个源代码来找到画布的可见区域。

我已经创建了这个应用程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Interop;


namespace MapDesigner.Controls
{
class MapCanvas : Canvas
{
    #region Routed Events
    public static readonly RoutedEvent SelectedColorChangeEvent = EventManager.RegisterRoutedEvent(
        "SelectedColorChange", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ucToolBox));
    public event RoutedEventHandler SelectedColorChange
    {
        add { AddHandler(SelectedColorChangeEvent, value); }
        remove { RemoveHandler(SelectedColorChangeEvent, value); }
    }
    #endregion

    #region Enums
    public enum Tool
    {

        Pencil,
        FloodFill,
        Eraser,
        RectSelect,
        Brush,
        Part
    }
    #endregion

    WriteableBitmap _wBMP;

    Image _dispImg = new Image();
    ScaleTransform st = new ScaleTransform();
    int canvasHeight, canvasWidth;
    double zoomLevel = 1;
    Border brdGrid = new Border();
    Color cellColor = Colors.Black;
    Tool currentTool = Tool.Pencil;
    int[,] array;
    bool drawing = false;
    bool showGrids = true;
    public TextBlock tbPos;

    public Tool CurrentTool
    {
        get
        {
            return currentTool;
        }
        set
        {
            currentTool = value;
        }
    }
    public Color CellColor
    {
        get
        {
            return cellColor;
        }
        set
        {
            cellColor = value;
        }
    }
    public bool GridsVisible
    {
        get
        {
            return showGrids;
        }
        set
        {
            showGrids = value;
        }
    }
    public MapCanvas()
    {

        this.Children.Clear();
        this.Children.Add(_dispImg);
        //st.ScaleX = 1;
        //st.ScaleY = 1;
        // this.LayoutTransform = st;
    }

    void Refresh()
    {
        //canvas = new MapCanvas();
        this.Children.Clear();
        this.Children.Add(_dispImg);
        st.ScaleX = 1;
        st.ScaleY = 1;
        this.Height = 0;
        this.Width = 0;
        zoomLevel = 1;
        drawing = false;
    }

    public void LoadBMP(Uri bmpUri)
    {
        Refresh();
        BitmapImage bmi = new BitmapImage(bmpUri);
        _wBMP = new WriteableBitmap(bmi);
        _dispImg.Source = _wBMP;
        this.Height = bmi.Height;
        this.Width = bmi.Width;
        ShowGrids();
    }

    public void CreateBMP(int width, int height)
    {
        Refresh();
        _wBMP = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr32, BitmapPalettes.WebPalette);
        _wBMP.setPixel(Colors.White);
        _dispImg.Source = _wBMP;
        this.Height = height;
        this.Width = width;
        ShowGrids();
    }

    public void CreateNewDesign(Size mapSize)
    {

        Refresh();            
        _wBMP = new WriteableBitmap((int)mapSize.Width, (int)mapSize.Width, 96, 96, PixelFormats.Bgr32, BitmapPalettes.WebPalette);
        _wBMP.setPixel(Colors.White);
        _dispImg.Source = _wBMP;
        array = new int[(_wBMP.PixelHeight + 1), (_wBMP.PixelWidth + 1)];
        canvasWidth = (int)mapSize.Width;
        canvasHeight = (int)mapSize.Height;
        this.Height = mapSize.Height;
        this.Width = mapSize.Width;
        ShowGrids();
    }

    void ShowGrids()
    {

        return;
        double width = 1;// _tileWidth + _tileMargin;
        double height = 1;// _tileHeight + _tileMargin;
        double numTileToAccumulate = 16;
        Polyline gridCell = new Polyline();
        gridCell.Margin = new Thickness(.5);
        gridCell.Stroke = Brushes.LightBlue;
        gridCell.StrokeThickness = 0.1;
        gridCell.Points = new PointCollection(new Point[] { new Point(0, height-0.1),
                    new Point(width-0.1, height-0.1), new Point(width-0.1, 0) });
        VisualBrush gridLines = new VisualBrush(gridCell);
        gridLines.TileMode = TileMode.Tile;
        gridLines.Viewport = new Rect(0, 0, 1.0 / numTileToAccumulate, 1.0 / numTileToAccumulate);
        gridLines.AlignmentX = AlignmentX.Center;
        gridLines.AlignmentY = AlignmentY.Center;

        VisualBrush outerVB = new VisualBrush();
        Rectangle outerRect = new Rectangle();
        outerRect.Width = 10.0;  //can be any size
        outerRect.Height = 10.0;
        outerRect.Fill = gridLines;
        outerVB.Visual = outerRect;
        outerVB.Viewport = new Rect(0, 0,
                width * numTileToAccumulate, height * numTileToAccumulate);
        outerVB.ViewportUnits = BrushMappingMode.Absolute;
        outerVB.TileMode = TileMode.Tile;
        this.Children.Remove(brdGrid);
        brdGrid = new Border();
        brdGrid.Height = this.Height;
        brdGrid.Width = this.Width;
        brdGrid.Background = outerVB;
        this.Children.Add(brdGrid);
    }

    protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
    {
        base.OnMouseMove(e);
        tbPos.Text = (_wBMP.PixelWidth / zoomLevel).ToString() + "," + (_wBMP.PixelHeight / zoomLevel).ToString() + " | " + Math.Ceiling((((Point)e.GetPosition(this)).X) / zoomLevel).ToString() + "," + Math.Ceiling((((Point)e.GetPosition(this)).Y / zoomLevel)).ToString();

        if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
        {
            Point pos = e.GetPosition(this);

            int xPos = (int)Math.Ceiling((pos.X) / zoomLevel);
            int yPos = (int)Math.Ceiling((pos.Y) / zoomLevel);

            int xDraw = (int)Math.Ceiling(pos.X);
            int yDraw = (int)Math.Ceiling(pos.Y);
            array[xPos, yPos] = 1;
            drawing = true;

            SetPixelsFromArray((int)zoomLevel);
            //for (int i = 0; i < zoomLevel; i++)
            //{
            //    for (int j = 0; j < zoomLevel; j++)
            //    {
            //        _wBMP.setPixel(xDraw, yDraw, cellColor);
            //        _dispImg.Source = _wBMP;

            //    }
            //}
            //_wBMP.setPixel(xPos, yPos, cellColor);
            //_wBMP.setPixel((int)pos.X, (int)pos.Y, cellColor);
            //_dispImg.Source = _wBMP;


        }
    }

    private void SetPixelsFromArray(int ZoomLevel)
    {

        for (int i = 1; i < _wBMP.PixelWidth / ZoomLevel; i++)
        {
            for (int j = 1; j < _wBMP.PixelHeight / ZoomLevel; j++)
            {
                if (array[i, j] == 1)
                {
                    for (int k = 0; k < ZoomLevel; k++)
                    {
                        for (int l = 0; l < ZoomLevel; l++)
                        {
                            _wBMP.setPixel((int)(i * ZoomLevel + k), (int)(j * ZoomLevel + l), cellColor);
                            _dispImg.Source = _wBMP;
                        }
                    }
                }
            }
        }
    }

    protected override void OnMouseUp(System.Windows.Input.MouseButtonEventArgs e)
    {

        //double d= this.ActualHeight;

        //Double t =(double) this.GetValue(Canvas.TopProperty);
        //double i = Convert.ToDouble(top);

        getScreenRect();
        if (e.ChangedButton == System.Windows.Input.MouseButton.Right)
        {
            if (cellColor == Colors.Black)
            {
                cellColor = Colors.Red;
            }
            else
            {
                cellColor = Colors.Black;
            }
        }
        else if (e.ChangedButton == System.Windows.Input.MouseButton.Left)
        {
            Point pos = e.GetPosition(this);
            int xPos = (int)Math.Ceiling((pos.X) / zoomLevel);
            int yPos = (int)Math.Ceiling((pos.Y) / zoomLevel);
            array[xPos, yPos] = 1;
            drawing = true;
            SetPixelsFromArray((int)zoomLevel);
            //_wBMP.setPixel((int)pos.X, (int)pos.Y, cellColor);
            //_dispImg.Source = _wBMP;


        }
    }

  private void getScreenRect()
  {
         Visual _rootVisual = HwndSource.FromVisual(this).RootVisual;


        GeneralTransform transformToRoot = this.TransformToAncestor(_rootVisual);

        Rect screenRect = new Rect(transformToRoot.Transform(new Point(0, 0)), transformToRoot.Transform(new Point(this.ActualWidth, this.ActualHeight)));

        DependencyObject parent = VisualTreeHelper.GetParent(this);

        while (parent != null)
        {

            Visual visual = parent as Visual;

            System.Windows.Controls.Control control = parent as System.Windows.Controls.Control;

            if (visual != null && control != null)
            {

                transformToRoot = visual.TransformToAncestor(_rootVisual);

                Point pointAncestorTopLeft = transformToRoot.Transform(new Point(0, 0));

                Point pointAncestorBottomRight = transformToRoot.Transform(new Point(control.ActualWidth, control.ActualHeight));

                Rect ancestorRect = new Rect(pointAncestorTopLeft, pointAncestorBottomRight);

                screenRect.Intersect(ancestorRect);

            }

            parent = VisualTreeHelper.GetParent(parent);

       //}

       // at this point screenRect is the bounding rectangle for the visible portion of "this" element
   }
   // return screenRect;


}
    protected override void OnMouseWheel(System.Windows.Input.MouseWheelEventArgs e)
    {

        base.OnMouseWheel(e);
        if (e.Delta > 0)
        {
            zoomLevel *= 2;
        }
        else
        {
            zoomLevel /= 2;
        }
        if (zoomLevel > 8)
        {
            zoomLevel = 8;
        }
        if (zoomLevel <= 1)
        {
            zoomLevel = 1;
            // brdGrid.Visibility = Visibility.Collapsed;
        }
        else
        {
            //brdGrid.Visibility = Visibility.Visible;
        }
        _wBMP = new WriteableBitmap((int)zoomLevel * canvasWidth, (int)zoomLevel * canvasHeight, 96, 96, PixelFormats.Bgr32, BitmapPalettes.WebPalette);
        _wBMP.setPixel(Colors.White);
        this.Width = zoomLevel * canvasWidth;
        this.Height = zoomLevel * canvasHeight;
        if (drawing == true)
        {
            SetPixelsFromArray((int)zoomLevel);
        }

        //this.InvalidateVisual();
    }

    internal bool SaveAsBMP(string fileName)
    {
        return true;
    }

}






    public static class bitmapextensions
    {
        public static void setPixel(this WriteableBitmap wbm, Color c)
        {

            if (!wbm.Format.Equals(PixelFormats.Bgr32))
                return;

            wbm.Lock();

            IntPtr buff = wbm.BackBuffer;
            int Stride = wbm.BackBufferStride;
            int x = 0;
            int y = 0;
            for (x = 0; x < wbm.PixelWidth; x++)
            {
                for (y = 0; y < wbm.PixelHeight; y++)
                {
                    unsafe
                    {

                        byte* pbuff = (byte*)buff.ToPointer();
                        int loc = y * Stride + x * 4;
                        pbuff[loc] = c.B;
                        pbuff[loc + 1] = c.G;
                        pbuff[loc + 2] = c.R;
                        //pbuff[loc + 3] = c.A;

                    }
                }
            }
            wbm.AddDirtyRect(new Int32Rect(0, 0, x, y));
            wbm.Unlock();
        }

        public static void setPixel(this WriteableBitmap wbm, int x, int y, Color c)
        {

            if (y > wbm.PixelHeight - 1 || x > wbm.PixelWidth - 1)
                return;

            if (y < 0 || x < 0)
                return;

            if (!wbm.Format.Equals(PixelFormats.Bgr32))
                return;

            wbm.Lock();

            IntPtr buff = wbm.BackBuffer;
            int Stride = wbm.BackBufferStride;

            unsafe
            {

                byte* pbuff = (byte*)buff.ToPointer();
                int loc = y * Stride + x * 4;
                pbuff[loc] = c.B;
                pbuff[loc + 1] = c.G;
                pbuff[loc + 2] = c.R;
                //pbuff[loc + 3] = c.A;

            }

            wbm.AddDirtyRect(new Int32Rect(x, y, 1, 1));
            wbm.Unlock();
        }

        public static Color getPixel(this WriteableBitmap wbm, int x, int y)
        {
            if (y > wbm.PixelHeight - 1 || x > wbm.PixelWidth - 1)
                return Color.FromArgb(0, 0, 0, 0);

            if (y < 0 || x < 0)
                return Color.FromArgb(0, 0, 0, 0);

            if (!wbm.Format.Equals(PixelFormats.Bgr32))
                return Color.FromArgb(0, 0, 0, 0);

            IntPtr buff = wbm.BackBuffer;
            int Stride = wbm.BackBufferStride;
            Color c;
            unsafe
            {
                byte* pbuff = (byte*)buff.ToPointer();
                int loc = y * Stride + x * 4;
                c = Color.FromArgb(pbuff[loc + 3], pbuff[loc + 2], pbuff[loc + 1], pbuff[loc]);
            }
            return c;
        }
    }
}

【问题讨论】:

    标签: wpf


    【解决方案1】:

    您应该在您的画布上实现IScrollInfo(或者实际上,创建一个继承自 Canvas 并实现 IScrollInfo 的自定义面板)。

    该界面包含与您的情况相关的所有内容:

    http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.iscrollinfo.aspx http://blogs.msdn.com/b/jgoldb/archive/2008/03/08/performant-virtualized-wpf-canvas.aspx

    【讨论】:

    • 谢谢你的帮助,如果你能给我一些代码,如何使用iscrollinfo,这对我有很大的帮助
    • 我给了你两个链接。只需 google IScrollInfo,您就会找到大量教程。
    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-15
    • 1970-01-01
    • 2012-01-22
    • 2017-06-06
    相关资源
    最近更新 更多