প্যান ও জুম চিত্র


130

আমি ডাব্লুপিএফ-তে একটি সাধারণ চিত্র প্রদর্শক তৈরি করতে চাই যা ব্যবহারকারীকে এতে সক্ষম করবে:

  • প্যান (মাউস ছবিটি টেনে আনার মাধ্যমে)।
  • জুম (একটি স্লাইডার সহ)।
  • ওভারলেগুলি দেখান (উদাহরণ হিসাবে আয়তক্ষেত্র নির্বাচন)।
  • আসল চিত্রটি দেখান (প্রয়োজনে স্ক্রোল বারগুলি সহ)।

আপনি কীভাবে এটি ব্যাখ্যা করতে পারেন?

ওয়েবে আমি কোনও ভাল নমুনা পাইনি। আমার ভিউবক্স ব্যবহার করা উচিত? নাকি ইমেজব্রাশ? আমার কি স্ক্রোলভিউয়ার দরকার?


ডব্লিউপিএফের জন্য পেশাদার জুম কন্ট্রোল পেতে জুমপ্যানেলটি দেখুন । এটি নিখরচায় নয়, তবে এটি ব্যবহার করা খুব সহজ এবং এর অনেকগুলি বৈশিষ্ট্য রয়েছে - অ্যানিমেটেড জুমিং এবং প্যানিং, স্ক্রোলভিউয়ারের জন্য সমর্থন, মাউস হুইল সমর্থন, জুমকন্ট্রোলার অন্তর্ভুক্ত (সরানো সহ, জুম ইন, জুম আউট, আয়তক্ষেত্রাকার জুম, রিসেট বোতাম)। এটি অনেক কোড নমুনা সঙ্গে আসে।
আন্দ্রেজ বেনেডিক

আমি ডাব্লুপিএফের জন্য একটি জুম এবং প্যান নিয়ন্ত্রণ বাস্তবায়নের বিষয়ে কোডড্রজেক্ট.কম এ একটি নিবন্ধ লিখেছিলাম। কোডেপ্রজেক্ট
অ্যাশলে ডেভিস

ভাল সন্ধান। নিখরচায় চেষ্টা করুন, এবং লাইসেন্সের জন্য তারা $ 69 / কম্পিউটার চান যদি আপনি এটির সাথে সফ্টওয়্যার তৈরি করতে চান। এটি ব্যবহারের জন্য একটি ডিএলএল, যাতে তারা আপনাকে থামাতে পারেনি, তবে এটিই যদি আপনি কোনও ক্লায়েন্টের জন্য বাণিজ্যিকভাবে এটি তৈরি করে থাকেন, বিশেষত কোনও তৃতীয় পক্ষের ইউটিলিটি ঘোষণার জন্য এবং স্বতন্ত্রভাবে লাইসেন্সপ্রাপ্ত হওয়ার জন্য আপনাকে অর্থ প্রদান করতে হবে উন্নয়ন ফি। EULA তে এটি "অ্যাপ্লিকেশন অনুযায়ী" ভিত্তিতে বলা হয়নি, যদিও আপনার ক্রয়টি নিবন্ধ করার সাথে সাথে এটি আপনার তৈরি সমস্ত অ্যাপ্লিকেশনগুলির জন্য "বিনামূল্যে" হবে এবং আপনার প্রদত্ত লাইসেন্স ফাইলটি অনুলিপি করতে পারে এটি ক্রয় প্রতিনিধিত্ব করতে।
vapcguy

উত্তর:


116

আমি এই সমস্যার সমাধানের উপায়টি হ'ল ক্লিপটোবাউন্ডসের সম্পত্তিটিকে সত্য হিসাবে সেট করে একটি চিত্র বর্ডারের মধ্যে রেখে দেওয়া। চিত্রটিতে রেন্ডার ট্রান্সফর্মআরগিনটি তার পরে 0.5,0.5 তে সেট করা থাকে যাতে চিত্রটি চিত্রের কেন্দ্রস্থলে জুম শুরু করে। রেন্ডার ট্রান্সফর্মটি একটি স্কেল ট্রান্সফর্ম এবং অনুবাদ অনুবাদ ট্রান্সফর্ম সমন্বিত ট্রান্সফর্ম গ্রুপেও সেট করা আছে।

আমি তখন জুমিং বাস্তবায়নের জন্য ইমেজটিতে মাউসওয়েল ইভেন্টটি পরিচালনা করেছি

private void image_MouseWheel(object sender, MouseWheelEventArgs e)
{
    var st = (ScaleTransform)image.RenderTransform;
    double zoom = e.Delta > 0 ? .2 : -.2;
    st.ScaleX += zoom;
    st.ScaleY += zoom;
}

প্যানিংয়ের প্রথম কাজটি হ্যান্ডেল করা আমি ইমেজটিতে মাউস লেফট বাটনডাউন ইভেন্ট হ্যান্ডেল করা, মাউস ক্যাপচার এবং এর অবস্থানটি রেকর্ড করার জন্য, আমি ট্রান্সলেট ট্রান্সফর্মের বর্তমান মানটিও সংরক্ষণ করি, এটি প্যানিং বাস্তবায়নের জন্য আপডেট করা হয়।

Point start;
Point origin;
private void image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    image.CaptureMouse();
    var tt = (TranslateTransform)((TransformGroup)image.RenderTransform)
        .Children.First(tr => tr is TranslateTransform);
    start = e.GetPosition(border);
    origin = new Point(tt.X, tt.Y);
}

তারপরে অনুবাদ অনুবাদ ট্রান্সফর্মটি আপডেট করতে আমি মাউসমোভ ইভেন্টটি পরিচালনা করেছি।

private void image_MouseMove(object sender, MouseEventArgs e)
{
    if (image.IsMouseCaptured)
    {
        var tt = (TranslateTransform)((TransformGroup)image.RenderTransform)
            .Children.First(tr => tr is TranslateTransform);
        Vector v = start - e.GetPosition(border);
        tt.X = origin.X - v.X;
        tt.Y = origin.Y - v.Y;
    }
}

অবশেষে মাউস ক্যাপচারটি প্রকাশ করতে ভুলবেন না।

private void image_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    image.ReleaseMouseCapture();
}

আকার পরিবর্তনের জন্য নির্বাচনের হ্যান্ডলগুলি কোনও অ্যাডোনারার ব্যবহার করে এটি সম্পন্ন করা যায়, আরও তথ্যের জন্য এই নিবন্ধটি দেখুন।


9
যদিও একটি পর্যবেক্ষণ, ইমেজ_মাউস লেফট বাটনডাউনে ক্যাপচারমাউসকে কল করার ফলে চিত্র_মাউসমাউমে কল আসবে যেখানে উত্সটি এখনও আরম্ভ করা হয়নি - উপরের কোডটিতে এটি শুদ্ধ সম্ভাবনা অনুসারে শূন্য হবে, তবে যদি উত্সটি (0,0) বাদে থাকে তবে চিত্রটি একটি সংক্ষিপ্ত লাফ অভিজ্ঞতা হবে। সুতরাং, আমি মনে করি ইমেজ কল করা ভাল। এই সমস্যাটি সমাধান করার জন্য চিত্র_মাউস লেফট বাটনডাউন শেষে ক্যাপচারমাউস ()।
আন্দ্রেই পানা

2
দুটি জিনিস. 1) চিত্র_মাউসওহিল সহ একটি ত্রুটি রয়েছে, আপনাকে অনুবাদ ট্রান্সফর্মটি একইভাবে স্কেল ট্রান্সফর্ম নিতে হবে। এটি, এটি একটি ট্রান্সফর্ম গ্রুপে কাস্ট করুন তারপরে উপযুক্ত শিশুটি নির্বাচন করুন এবং কাস্ট করুন। 2) যদি আপনার আন্দোলনটি জিটারি মনে থাকে তবে আপনি নিজের মাউস অবস্থানটি পেতে চিত্রটি ব্যবহার করতে পারবেন না (যেহেতু এটি গতিশীল), আপনাকে স্ট্যাটিক কিছু ব্যবহার করতে হবে। এই উদাহরণে, একটি সীমানা ব্যবহৃত হয়।
ডেভ

169

এই প্রশ্নটি থেকে নমুনা ব্যবহার করার পরে আমি মাউস পয়েন্টারের তুলনায় উপযুক্ত জুমিং সহ প্যান ও জুম অ্যাপের সম্পূর্ণ সংস্করণ তৈরি করেছি complete সমস্ত প্যান ও জুম কোড পৃথক শ্রেণিতে সরানো হয়েছে জুমবারর্ডার।

ZoomBorder.cs

using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace PanAndZoom
{
  public class ZoomBorder : Border
  {
    private UIElement child = null;
    private Point origin;
    private Point start;

    private TranslateTransform GetTranslateTransform(UIElement element)
    {
      return (TranslateTransform)((TransformGroup)element.RenderTransform)
        .Children.First(tr => tr is TranslateTransform);
    }

    private ScaleTransform GetScaleTransform(UIElement element)
    {
      return (ScaleTransform)((TransformGroup)element.RenderTransform)
        .Children.First(tr => tr is ScaleTransform);
    }

    public override UIElement Child
    {
      get { return base.Child; }
      set
      {
        if (value != null && value != this.Child)
          this.Initialize(value);
        base.Child = value;
      }
    }

    public void Initialize(UIElement element)
    {
      this.child = element;
      if (child != null)
      {
        TransformGroup group = new TransformGroup();
        ScaleTransform st = new ScaleTransform();
        group.Children.Add(st);
        TranslateTransform tt = new TranslateTransform();
        group.Children.Add(tt);
        child.RenderTransform = group;
        child.RenderTransformOrigin = new Point(0.0, 0.0);
        this.MouseWheel += child_MouseWheel;
        this.MouseLeftButtonDown += child_MouseLeftButtonDown;
        this.MouseLeftButtonUp += child_MouseLeftButtonUp;
        this.MouseMove += child_MouseMove;
        this.PreviewMouseRightButtonDown += new MouseButtonEventHandler(
          child_PreviewMouseRightButtonDown);
      }
    }

    public void Reset()
    {
      if (child != null)
      {
        // reset zoom
        var st = GetScaleTransform(child);
        st.ScaleX = 1.0;
        st.ScaleY = 1.0;

        // reset pan
        var tt = GetTranslateTransform(child);
        tt.X = 0.0;
        tt.Y = 0.0;
      }
    }

    #region Child Events

        private void child_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (child != null)
            {
                var st = GetScaleTransform(child);
                var tt = GetTranslateTransform(child);

                double zoom = e.Delta > 0 ? .2 : -.2;
                if (!(e.Delta > 0) && (st.ScaleX < .4 || st.ScaleY < .4))
                    return;

                Point relative = e.GetPosition(child);
                double absoluteX;
                double absoluteY;

                absoluteX = relative.X * st.ScaleX + tt.X;
                absoluteY = relative.Y * st.ScaleY + tt.Y;

                st.ScaleX += zoom;
                st.ScaleY += zoom;

                tt.X = absoluteX - relative.X * st.ScaleX;
                tt.Y = absoluteY - relative.Y * st.ScaleY;
            }
        }

        private void child_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (child != null)
            {
                var tt = GetTranslateTransform(child);
                start = e.GetPosition(this);
                origin = new Point(tt.X, tt.Y);
                this.Cursor = Cursors.Hand;
                child.CaptureMouse();
            }
        }

        private void child_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (child != null)
            {
                child.ReleaseMouseCapture();
                this.Cursor = Cursors.Arrow;
            }
        }

        void child_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.Reset();
        }

        private void child_MouseMove(object sender, MouseEventArgs e)
        {
            if (child != null)
            {
                if (child.IsMouseCaptured)
                {
                    var tt = GetTranslateTransform(child);
                    Vector v = start - e.GetPosition(this);
                    tt.X = origin.X - v.X;
                    tt.Y = origin.Y - v.Y;
                }
            }
        }

        #endregion
    }
}

MainWindow.xaml

<Window x:Class="PanAndZoom.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:PanAndZoom"
        Title="PanAndZoom" Height="600" Width="900" WindowStartupLocation="CenterScreen">
    <Grid>
        <local:ZoomBorder x:Name="border" ClipToBounds="True" Background="Gray">
            <Image Source="image.jpg"/>
        </local:ZoomBorder>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
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 PanAndZoom
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

10
দুঃখের বিষয়, আমি আপনাকে আরও বক্তব্য দিতে পারি না। এটি সত্যিই দুর্দান্ত কাজ করে।
টবিয়েল

6
"চমৎকার কাজ!" এর জন্য মন্তব্যগুলি ব্লক হওয়ার আগে! বা "গ্রেট ওয়ার্ক" আমি কেবল নিস জব এবং গ্রেট ওয়ার্ক বলতে চাই। এটি একটি ডাব্লুপিএফ রত্ন। এটি ডাব্লুপিএফ এক্সট্রা জুমবক্সটি পানির বাইরে ফেলে দেয়।
জেসি সেগার

4
আউট দাঁড়িয়ে। আমি এখনও আজ রাতে বাড়িতে যেতে সক্ষম হতে পারি ... +1000
ব্রুস পাইয়ারসন

1
অসাধারণ. আমি এই ধরনের বাস্তবায়ন সম্পর্কে যদিও করি নি তবে এটি সত্যিই দুর্দান্ত! তোমাকে অনেক ধন্যবাদ!
নোয়েল ওয়াইডার

3
দুর্দান্ত উত্তর! আমি জুম ফ্যাক্টরের সাথে সামান্য সংশোধন যোগ করেছি, সুতরাং এটি "ধীর" জুম করে নাdouble zoomCorrected = zoom*st.ScaleX; st.ScaleX += zoomCorrected; st.ScaleY += zoomCorrected;
16-24 এ DELUXEnized

46

উত্তর উপরে পোস্ট করা হয়েছিল কিন্তু সম্পূর্ণ ছিল না। এখানে সম্পূর্ণ সংস্করণ:

XAML

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MapTest.Window1"
x:Name="Window"
Title="Window1"
Width="1950" Height="1546" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:Controls="clr-namespace:WPFExtensions.Controls;assembly=WPFExtensions" mc:Ignorable="d" Background="#FF000000">

<Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
        <RowDefinition Height="52.92"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <Border Grid.Row="1" Name="border">
        <Image Name="image" Source="map3-2.png" Opacity="1" RenderTransformOrigin="0.5,0.5"  />
    </Border>

</Grid>

পিছনে কোড

using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace MapTest
{
    public partial class Window1 : Window
    {
        private Point origin;
        private Point start;

        public Window1()
        {
            InitializeComponent();

            TransformGroup group = new TransformGroup();

            ScaleTransform xform = new ScaleTransform();
            group.Children.Add(xform);

            TranslateTransform tt = new TranslateTransform();
            group.Children.Add(tt);

            image.RenderTransform = group;

            image.MouseWheel += image_MouseWheel;
            image.MouseLeftButtonDown += image_MouseLeftButtonDown;
            image.MouseLeftButtonUp += image_MouseLeftButtonUp;
            image.MouseMove += image_MouseMove;
        }

        private void image_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            image.ReleaseMouseCapture();
        }

        private void image_MouseMove(object sender, MouseEventArgs e)
        {
            if (!image.IsMouseCaptured) return;

            var tt = (TranslateTransform) ((TransformGroup) image.RenderTransform).Children.First(tr => tr is TranslateTransform);
            Vector v = start - e.GetPosition(border);
            tt.X = origin.X - v.X;
            tt.Y = origin.Y - v.Y;
        }

        private void image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            image.CaptureMouse();
            var tt = (TranslateTransform) ((TransformGroup) image.RenderTransform).Children.First(tr => tr is TranslateTransform);
            start = e.GetPosition(border);
            origin = new Point(tt.X, tt.Y);
        }

        private void image_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            TransformGroup transformGroup = (TransformGroup) image.RenderTransform;
            ScaleTransform transform = (ScaleTransform) transformGroup.Children[0];

            double zoom = e.Delta > 0 ? .2 : -.2;
            transform.ScaleX += zoom;
            transform.ScaleY += zoom;
        }
    }
}

আমার ওয়েবসাইটে এই কোডটি ব্যবহার করে একটি পূর্ণ wpf প্রকল্পের উদাহরণ রয়েছে: স্টিকি নোট অ্যাপটি জোট করুন


1
সিলভারলাইট 3 এ কীভাবে এটি ব্যবহারযোগ্য করে তোলা যায় সে সম্পর্কে কোনও পরামর্শ? ভেক্টর এবং অন্য থেকে একটি পয়েন্ট বিয়োগ করতে আমার সমস্যা আছে ... ধন্যবাদ
8

@ সংখ্যা 8 নীচে আপনার জন্য সিলভারলাইট 3 তে কাজ করে এমন একটি বাস্তবায়ন পোস্ট করেছে :)
হেনরি সি

4
একটি ছোট্ট অসুবিধা - চিত্রটি সীমান্তের সাথে বেড়েছে , এবং সীমান্তের অভ্যন্তরে নয়
ইশশো

আপনি কি ছেলেরা উইন্ডোজ 8 মেট্রো স্টাইলের অ্যাপটিতে একই জিনিস বাস্তবায়নের জন্য কিছু পরামর্শ দিতে পারেন .. আমি সি # তে কাজ করছি, উইন্ডোজ 8-এ এক্সএএমএল
রাজ

1
চিত্র_মাউসওয়েলে আপনি ট্রান্সফর্মটি পরীক্ষা করতে পারেন c স্কেলএক্স এবং স্কেলওয়াই মানগুলি এবং যদি সেই মানগুলি + জুম> আপনার সীমা থাকে তবে + = জুম লাইনগুলি প্রয়োগ করবেন না।
কেলি

10

এই জুম কন্ট্রোলটি ব্যবহার করে দেখুন: http://wpfextensions.codeplex.com

নিয়ন্ত্রণটির ব্যবহার খুব সহজ, ডাব্লুপিএফএফটি এক্সটেনশানস সমাবেশের চেয়ে উল্লেখ:

<wpfext:ZoomControl>
    <Image Source="..."/>
</wpfext:ZoomControl>

এই মুহুর্তে স্ক্রোলবারগুলি সমর্থিত নয়। (এটি পরবর্তী প্রকাশে হবে যা এক বা দুই সপ্তাহের মধ্যে পাওয়া যাবে)।


হ্যাঁ, উপভোগ করছি। আপনার বাকি লাইব্রেরি যদিও বেশ তুচ্ছ।
এশিউইন iteক্যবদ্ধ

যদিও 'ওভারলেগুলি দেখান (উদাহরণ হিসাবে আয়তক্ষেত্র নির্বাচন)' এর জন্য সরাসরি সমর্থন বলে মনে হয় না তবে জুম / প্যানিং আচরণের জন্য এটি দুর্দান্ত নিয়ন্ত্রণ।
jsirr13

9
  • প্যান: চিত্রটি একটি ক্যানভাসের ভিতরে রাখুন। ক্যানভাস.টপ, ক্যানভাস। বাম বৈশিষ্ট্যগুলি সরানোর জন্য মাউস আপ, ডাউন এবং ইভেন্টগুলি সরান। নীচে নেমে গেলে আপনি একটি আইড্রেগিংফ্লেগকে সত্য হিসাবে চিহ্নিত করেন, যখন আপনি পতাকাটিকে মিথ্যাতে সেট করেন। চলার সময়, আপনি পতাকাটি সেট করা আছে কিনা তা পরীক্ষা করে দেখুন, এটি যদি আপনি ক্যানভাসে রাখেন op টপ এবং ক্যানভাস। ক্যানভাসের মধ্যে থাকা চিত্রের বাম বৈশিষ্ট্যগুলি।
  • জুম: স্লাইডারটি ক্যানভাসের স্কেল ট্রান্সফর্মটিতে আবদ্ধ করুন
  • ওভারলেগুলি দেখান: চিত্রযুক্ত ক্যানভাসের উপরে কোনও পটভূমি ছাড়াই অতিরিক্ত ক্যানভাস যুক্ত করুন।
  • আসল চিত্রটি দেখান: ভিউবক্সের অভ্যন্তরে চিত্র নিয়ন্ত্রণ

4

@ অ্যানথেন এবং @ নম্বর 8 - ভেক্টর শ্রেণি সিলভারলাইটে উপলভ্য নয়, সুতরাং এটি কাজ করার জন্য আমাদের মাউসমোভ ইভেন্টটি ডাকাবার সময় সর্বনিম্ন অবস্থানের রেকর্ড রাখতে হবে এবং পার্থক্যটি খুঁজতে দুটি পয়েন্টের তুলনা করতে হবে ; তারপরে ট্রান্সফর্মটি সামঞ্জস্য করুন।

XAML:

    <Border Name="viewboxBackground" Background="Black">
            <Viewbox Name="viewboxMain">
                <!--contents go here-->
            </Viewbox>
    </Border>  

কোড-পিছনে:

    public Point _mouseClickPos;
    public bool bMoving;


    public MainPage()
    {
        InitializeComponent();
        viewboxMain.RenderTransform = new CompositeTransform();
    }

    void MouseMoveHandler(object sender, MouseEventArgs e)
    {

        if (bMoving)
        {
            //get current transform
            CompositeTransform transform = viewboxMain.RenderTransform as CompositeTransform;

            Point currentPos = e.GetPosition(viewboxBackground);
            transform.TranslateX += (currentPos.X - _mouseClickPos.X) ;
            transform.TranslateY += (currentPos.Y - _mouseClickPos.Y) ;

            viewboxMain.RenderTransform = transform;

            _mouseClickPos = currentPos;
        }            
    }

    void MouseClickHandler(object sender, MouseButtonEventArgs e)
    {
        _mouseClickPos = e.GetPosition(viewboxBackground);
        bMoving = true;
    }

    void MouseReleaseHandler(object sender, MouseButtonEventArgs e)
    {
        bMoving = false;
    }

এছাড়াও নোট করুন যে প্যান এবং জুম বাস্তবায়নের জন্য আপনার কোনও ট্রান্সফর্ম গ্রুপ বা সংগ্রহের প্রয়োজন নেই; পরিবর্তে, একটি কম্পোজিট ট্রান্সফর্ম কম ঝামেলা করে কৌশলটি করবে।

আমি যথেষ্ট নিশ্চিত যে এটি সম্পদ ব্যবহারের ক্ষেত্রে সত্যই অদক্ষ, তবে কমপক্ষে এটি কার্যকর হয় :)


2

মাউসের অবস্থানের তুলনায় জুম করতে, আপনার যা প্রয়োজন তা হ'ল:

var position = e.GetPosition(image1);
image1.RenderTransformOrigin = new Point(position.X / image1.ActualWidth, position.Y / image1.ActualHeight);

আমি পিকচারবক্স ব্যবহার করছি, রেন্ডারট্রান্সফর্মআরগিনের আর অস্তিত্ব নেই।
সুইচ

@ সুইচ রেন্ডারট্রান্সফর্মআরগিন ডাব্লুপিএফ নিয়ন্ত্রণের জন্য।
জ্যাম

2

@ Merk

ল্যাম্বডা এক্সপ্রেশন দ্বারা নিহিত আপনার সমাধানের জন্য আপনি নিম্নলিখিত কোডটি ব্যবহার করতে পারেন:

//var tt = (TranslateTransform)((TransformGroup)image.RenderTransform).Children.First(tr => tr is TranslateTransform);
        TranslateTransform tt = null;
        TransformGroup transformGroup = (TransformGroup)grid.RenderTransform;
        for (int i = 0; i < transformGroup.Children.Count; i++)
        {
            if (transformGroup.Children[i] is TranslateTransform)
                tt = (TranslateTransform)transformGroup.Children[i];
        }

এই কোডটি নেট ফ্রেমের কাজ হিসাবে 3.0.০ বা 2.0 এর মতো ব্যবহার করা যেতে পারে

আশা করি এটি আপনাকে সহায়তা করে :-)


2

তবুও একই ধরণের নিয়ন্ত্রণের আরেকটি সংস্করণ। অন্যান্যদের মতো এটির কার্যকারিতা রয়েছে তবে এটি যুক্ত করে:

  1. সমর্থন স্পর্শ (টানুন / চিমটি)
  2. চিত্রটি মোছা যায় (সাধারণত, চিত্র নিয়ন্ত্রণটি চিত্রটিকে ডিস্কে লক করে দেয়, তাই আপনি এটি মুছতে পারবেন না)।
  3. একটি অভ্যন্তরীণ সীমান্তের শিশু, যাতে প্যানড ইমেজটি সীমানাকে অতিক্রম করে না। বৃত্তাকার আয়তক্ষেত্রগুলির সীমানার ক্ষেত্রে ক্লিপবোর্ডার ক্লাসগুলি সন্ধান করুন।

ব্যবহার সহজ:

<Controls:ImageViewControl ImagePath="{Binding ...}" />

এবং কোড:

public class ImageViewControl : Border
{
    private Point origin;
    private Point start;
    private Image image;

    public ImageViewControl()
    {
        ClipToBounds = true;
        Loaded += OnLoaded;
    }

    #region ImagePath

    /// <summary>
    ///     ImagePath Dependency Property
    /// </summary>
    public static readonly DependencyProperty ImagePathProperty = DependencyProperty.Register("ImagePath", typeof (string), typeof (ImageViewControl), new FrameworkPropertyMetadata(string.Empty, OnImagePathChanged));

    /// <summary>
    ///     Gets or sets the ImagePath property. This dependency property 
    ///     indicates the path to the image file.
    /// </summary>
    public string ImagePath
    {
        get { return (string) GetValue(ImagePathProperty); }
        set { SetValue(ImagePathProperty, value); }
    }

    /// <summary>
    ///     Handles changes to the ImagePath property.
    /// </summary>
    private static void OnImagePathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (ImageViewControl) d;
        var oldImagePath = (string) e.OldValue;
        var newImagePath = target.ImagePath;
        target.ReloadImage(newImagePath);
        target.OnImagePathChanged(oldImagePath, newImagePath);
    }

    /// <summary>
    ///     Provides derived classes an opportunity to handle changes to the ImagePath property.
    /// </summary>
    protected virtual void OnImagePathChanged(string oldImagePath, string newImagePath)
    {
    }

    #endregion

    private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
        image = new Image {
                              //IsManipulationEnabled = true,
                              RenderTransformOrigin = new Point(0.5, 0.5),
                              RenderTransform = new TransformGroup {
                                                                       Children = new TransformCollection {
                                                                                                              new ScaleTransform(),
                                                                                                              new TranslateTransform()
                                                                                                          }
                                                                   }
                          };
        // NOTE I use a border as the first child, to which I add the image. I do this so the panned image doesn't partly obscure the control's border.
        // In case you are going to use rounder corner's on this control, you may to update your clipping, as in this example:
        // http://wpfspark.wordpress.com/2011/06/08/clipborder-a-wpf-border-that-clips/
        var border = new Border {
                                    IsManipulationEnabled = true,
                                    ClipToBounds = true,
                                    Child = image
                                };
        Child = border;

        image.MouseWheel += (s, e) =>
                                {
                                    var zoom = e.Delta > 0
                                                   ? .2
                                                   : -.2;
                                    var position = e.GetPosition(image);
                                    image.RenderTransformOrigin = new Point(position.X / image.ActualWidth, position.Y / image.ActualHeight);
                                    var st = (ScaleTransform)((TransformGroup)image.RenderTransform).Children.First(tr => tr is ScaleTransform);
                                    st.ScaleX += zoom;
                                    st.ScaleY += zoom;
                                    e.Handled = true;
                                };

        image.MouseLeftButtonDown += (s, e) =>
                                         {
                                             if (e.ClickCount == 2)
                                                 ResetPanZoom();
                                             else
                                             {
                                                 image.CaptureMouse();
                                                 var tt = (TranslateTransform) ((TransformGroup) image.RenderTransform).Children.First(tr => tr is TranslateTransform);
                                                 start = e.GetPosition(this);
                                                 origin = new Point(tt.X, tt.Y);
                                             }
                                             e.Handled = true;
                                         };

        image.MouseMove += (s, e) =>
                               {
                                   if (!image.IsMouseCaptured) return;
                                   var tt = (TranslateTransform) ((TransformGroup) image.RenderTransform).Children.First(tr => tr is TranslateTransform);
                                   var v = start - e.GetPosition(this);
                                   tt.X = origin.X - v.X;
                                   tt.Y = origin.Y - v.Y;
                                   e.Handled = true;
                               };

        image.MouseLeftButtonUp += (s, e) => image.ReleaseMouseCapture();

        //NOTE I apply the manipulation to the border, and not to the image itself (which caused stability issues when translating)!
        border.ManipulationDelta += (o, e) =>
                                       {
                                           var st = (ScaleTransform)((TransformGroup)image.RenderTransform).Children.First(tr => tr is ScaleTransform);
                                           var tt = (TranslateTransform)((TransformGroup)image.RenderTransform).Children.First(tr => tr is TranslateTransform);

                                           st.ScaleX *= e.DeltaManipulation.Scale.X;
                                           st.ScaleY *= e.DeltaManipulation.Scale.X;
                                           tt.X += e.DeltaManipulation.Translation.X;
                                           tt.Y += e.DeltaManipulation.Translation.Y;

                                           e.Handled = true;
                                       };
    }

    private void ResetPanZoom()
    {
        var st = (ScaleTransform)((TransformGroup)image.RenderTransform).Children.First(tr => tr is ScaleTransform);
        var tt = (TranslateTransform)((TransformGroup)image.RenderTransform).Children.First(tr => tr is TranslateTransform);
        st.ScaleX = st.ScaleY = 1;
        tt.X = tt.Y = 0;
        image.RenderTransformOrigin = new Point(0.5, 0.5);
    }

    /// <summary>
    /// Load the image (and do not keep a hold on it, so we can delete the image without problems)
    /// </summary>
    /// <see cref="http://blogs.vertigo.com/personal/ralph/Blog/Lists/Posts/Post.aspx?ID=18"/>
    /// <param name="path"></param>
    private void ReloadImage(string path)
    {
        try
        {
            ResetPanZoom();
            // load the image, specify CacheOption so the file is not locked
            var bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
            bitmapImage.UriSource = new Uri(path, UriKind.RelativeOrAbsolute);
            bitmapImage.EndInit();
            image.Source = bitmapImage;
        }
        catch (SystemException e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

1
কেবলমাত্র আমি খুঁজে পেলাম সমস্যাটি হ'ল যদি কোনও চিত্রের পাথ এক্সএএমএল-তে নির্দিষ্ট করা থাকে তবে চিত্র চিত্রটি নির্মাণের আগে এটি অর্থাত্ রেন্ডার করার চেষ্টা করে (যেমন অনোলয়েড বলার আগে)। ঠিক করার জন্য, আমি অন্লোড পদ্ধতিতে "চিত্র = নতুন চিত্র ..." কোডটি কনস্ট্রাক্টরে স্থানান্তরিত করেছি। ধন্যবাদ।
ম্যাচ

অন্য সমস্যাটি হ'ল চিত্রটি ছোট হয়ে উঠতে পারে যতক্ষণ না আমরা কিছু না করতে পারি এবং কিছুই দেখতে পাই না if (image.ActualWidth*(st.ScaleX + zoom) < 200 || image.ActualHeight*(st.ScaleY + zoom) < 200) //don't zoom out too small. return;I আমি কিছুটা সীমাবদ্ধতা যুক্ত করি: চিত্রটিতে inমাউস হুইল
হুওকুডং 125

1

এটি প্যানের পাশাপাশি জুম বাড়িয়ে আউট করবে তবে চিত্রটি পাত্রে রাখবে। একটি নিয়ন্ত্রণ হিসাবে রচনা তাই App.xamlসরাসরি বা মাধ্যমে স্টাইল যুক্ত করুন Themes/Viewport.xaml

পাঠযোগ্যতার জন্য আমি এটি গিস্ট এবং গিথুবেও আপলোড করেছি

আমি এটি নুগেটেও প্যাকেজ করেছি

PM > Install-Package Han.Wpf.ViewportControl

./Controls/Viewport.cs:

public class Viewport : ContentControl
{
    private bool _capture;
    private FrameworkElement _content;
    private Matrix _matrix;
    private Point _origin;

    public static readonly DependencyProperty MaxZoomProperty =
        DependencyProperty.Register(
            nameof(MaxZoom),
            typeof(double),
            typeof(Viewport),
            new PropertyMetadata(0d));

    public static readonly DependencyProperty MinZoomProperty =
        DependencyProperty.Register(
            nameof(MinZoom),
            typeof(double),
            typeof(Viewport),
            new PropertyMetadata(0d));

    public static readonly DependencyProperty ZoomSpeedProperty =
        DependencyProperty.Register(
            nameof(ZoomSpeed),
            typeof(float),
            typeof(Viewport),
            new PropertyMetadata(0f));

    public static readonly DependencyProperty ZoomXProperty =
        DependencyProperty.Register(
            nameof(ZoomX),
            typeof(double),
            typeof(Viewport),
            new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public static readonly DependencyProperty ZoomYProperty =
        DependencyProperty.Register(
            nameof(ZoomY),
            typeof(double),
            typeof(Viewport),
            new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public static readonly DependencyProperty OffsetXProperty =
        DependencyProperty.Register(
            nameof(OffsetX),
            typeof(double),
            typeof(Viewport),
            new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public static readonly DependencyProperty OffsetYProperty =
        DependencyProperty.Register(
            nameof(OffsetY),
            typeof(double),
            typeof(Viewport),
            new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public static readonly DependencyProperty BoundsProperty =
        DependencyProperty.Register(
            nameof(Bounds),
            typeof(Rect),
            typeof(Viewport),
            new FrameworkPropertyMetadata(default(Rect), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public Rect Bounds
    {
        get => (Rect) GetValue(BoundsProperty);
        set => SetValue(BoundsProperty, value);
    }

    public double MaxZoom
    {
        get => (double) GetValue(MaxZoomProperty);
        set => SetValue(MaxZoomProperty, value);
    }

    public double MinZoom
    {
        get => (double) GetValue(MinZoomProperty);
        set => SetValue(MinZoomProperty, value);
    }

    public double OffsetX
    {
        get => (double) GetValue(OffsetXProperty);
        set => SetValue(OffsetXProperty, value);
    }

    public double OffsetY
    {
        get => (double) GetValue(OffsetYProperty);
        set => SetValue(OffsetYProperty, value);
    }

    public float ZoomSpeed
    {
        get => (float) GetValue(ZoomSpeedProperty);
        set => SetValue(ZoomSpeedProperty, value);
    }

    public double ZoomX
    {
        get => (double) GetValue(ZoomXProperty);
        set => SetValue(ZoomXProperty, value);
    }

    public double ZoomY
    {
        get => (double) GetValue(ZoomYProperty);
        set => SetValue(ZoomYProperty, value);
    }

    public Viewport()
    {
        DefaultStyleKey = typeof(Viewport);

        Loaded += OnLoaded;
        Unloaded += OnUnloaded;
    }

    private void Arrange(Size desired, Size render)
    {
        _matrix = Matrix.Identity;

        var zx = desired.Width / render.Width;
        var zy = desired.Height / render.Height;
        var cx = render.Width < desired.Width ? render.Width / 2.0 : 0.0;
        var cy = render.Height < desired.Height ? render.Height / 2.0 : 0.0;

        var zoom = Math.Min(zx, zy);

        if (render.Width > desired.Width &&
            render.Height > desired.Height)
        {
            cx = (desired.Width - (render.Width * zoom)) / 2.0;
            cy = (desired.Height - (render.Height * zoom)) / 2.0;

            _matrix = new Matrix(zoom, 0d, 0d, zoom, cx, cy);
        }
        else
        {
            _matrix.ScaleAt(zoom, zoom, cx, cy);
        }
    }

    private void Attach(FrameworkElement content)
    {
        content.MouseMove += OnMouseMove;
        content.MouseLeave += OnMouseLeave;
        content.MouseWheel += OnMouseWheel;
        content.MouseLeftButtonDown += OnMouseLeftButtonDown;
        content.MouseLeftButtonUp += OnMouseLeftButtonUp;
        content.SizeChanged += OnSizeChanged;
        content.MouseRightButtonDown += OnMouseRightButtonDown;
    }

    private void ChangeContent(FrameworkElement content)
    {
        if (content != null && !Equals(content, _content))
        {
            if (_content != null)
            {
                Detatch();
            }

            Attach(content);
            _content = content;
        }
    }

    private double Constrain(double value, double min, double max)
    {
        if (min > max)
        {
            min = max;
        }

        if (value <= min)
        {
            return min;
        }

        if (value >= max)
        {
            return max;
        }

        return value;
    }

    private void Constrain()
    {
        var x = Constrain(_matrix.OffsetX, _content.ActualWidth - _content.ActualWidth * _matrix.M11, 0);
        var y = Constrain(_matrix.OffsetY, _content.ActualHeight - _content.ActualHeight * _matrix.M22, 0);

        _matrix = new Matrix(_matrix.M11, 0d, 0d, _matrix.M22, x, y);
    }

    private void Detatch()
    {
        _content.MouseMove -= OnMouseMove;
        _content.MouseLeave -= OnMouseLeave;
        _content.MouseWheel -= OnMouseWheel;
        _content.MouseLeftButtonDown -= OnMouseLeftButtonDown;
        _content.MouseLeftButtonUp -= OnMouseLeftButtonUp;
        _content.SizeChanged -= OnSizeChanged;
        _content.MouseRightButtonDown -= OnMouseRightButtonDown;
    }

    private void Invalidate()
    {
        if (_content != null)
        {
            Constrain();

            _content.RenderTransformOrigin = new Point(0, 0);
            _content.RenderTransform = new MatrixTransform(_matrix);
            _content.InvalidateVisual();

            ZoomX = _matrix.M11;
            ZoomY = _matrix.M22;

            OffsetX = _matrix.OffsetX;
            OffsetY = _matrix.OffsetY;

            var rect = new Rect
            {
                X = OffsetX * -1,
                Y = OffsetY * -1,
                Width = ActualWidth,
                Height = ActualHeight
            };

            Bounds = rect;
        }
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        _matrix = Matrix.Identity;
    }

    protected override void OnContentChanged(object oldContent, object newContent)
    {
        base.OnContentChanged(oldContent, newContent);

        if (Content is FrameworkElement element)
        {
            ChangeContent(element);
        }
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        if (Content is FrameworkElement element)
        {
            ChangeContent(element);
        }

        SizeChanged += OnSizeChanged;
        Loaded -= OnLoaded;
    }

    private void OnMouseLeave(object sender, MouseEventArgs e)
    {
        if (_capture)
        {
            Released();
        }
    }

    private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (IsEnabled && !_capture)
        {
            Pressed(e.GetPosition(this));
        }
    }

    private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (IsEnabled && _capture)
        {
            Released();
        }
    }

    private void OnMouseMove(object sender, MouseEventArgs e)
    {
        if (IsEnabled && _capture)
        {
            var position = e.GetPosition(this);

            var point = new Point
            {
                X = position.X - _origin.X,
                Y = position.Y - _origin.Y
            };

            var delta = point;
            _origin = position;

            _matrix.Translate(delta.X, delta.Y);

            Invalidate();
        }
    }

    private void OnMouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (IsEnabled)
        {
            Reset();
        }
    }

    private void OnMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (IsEnabled)
        {
            var scale = e.Delta > 0 ? ZoomSpeed : 1 / ZoomSpeed;
            var position = e.GetPosition(_content);

            var x = Constrain(scale, MinZoom / _matrix.M11, MaxZoom / _matrix.M11);
            var y = Constrain(scale, MinZoom / _matrix.M22, MaxZoom / _matrix.M22);

            _matrix.ScaleAtPrepend(x, y, position.X, position.Y);

            ZoomX = _matrix.M11;
            ZoomY = _matrix.M22;

            Invalidate();
        }
    }

    private void OnSizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (_content?.IsMeasureValid ?? false)
        {
            Arrange(_content.DesiredSize, _content.RenderSize);

            Invalidate();
        }
    }

    private void OnUnloaded(object sender, RoutedEventArgs e)
    {
        Detatch();

        SizeChanged -= OnSizeChanged;
        Unloaded -= OnUnloaded;
    }

    private void Pressed(Point position)
    {
        if (IsEnabled)
        {
            _content.Cursor = Cursors.Hand;
            _origin = position;
            _capture = true;
        }
    }

    private void Released()
    {
        if (IsEnabled)
        {
            _content.Cursor = null;
            _capture = false;
        }
    }

    private void Reset()
    {
        _matrix = Matrix.Identity;

        if (_content != null)
        {
            Arrange(_content.DesiredSize, _content.RenderSize);
        }

        Invalidate();
    }
}

./Themes/Viewport.xaml:

<ResourceDictionary ... >

    <Style TargetType="{x:Type controls:Viewport}"
           BasedOn="{StaticResource {x:Type ContentControl}}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type controls:Viewport}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Background="{TemplateBinding Background}">
                        <Grid ClipToBounds="True"
                              Width="{TemplateBinding Width}"
                              Height="{TemplateBinding Height}">
                            <Grid x:Name="PART_Container">
                                <ContentPresenter x:Name="PART_Presenter" />
                            </Grid>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

./App.xaml

<Application ... >
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>

                <ResourceDictionary Source="./Themes/Viewport.xaml"/>

            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

ব্যবহার:

<viewers:Viewport>
    <Image Source="{Binding}"/>
</viewers:Viewport>

কোন সমস্যা, আমাকে চিৎকার করুন।

শুভ কোডিং :)


দুর্দান্ত, আমি এই সংস্করণটি ভালবাসি। এতে কোনও স্ক্রোলবার যুক্ত করার উপায়?
এটিয়েন চার্ল্যান্ড

উপায় দ্বারা আপনি নির্ভরতা বৈশিষ্ট্য ভুল ব্যবহার করছেন। জুম এবং অনুবাদ এর জন্য, কোডটি প্রপার্টি সেটারে রাখতে পারবেন না কারণ বাঁধাইয়ের সময় এটি কল হয় না। নির্ভরতা সম্পত্তিতে নিজেই পরিবর্তন এবং সহকারী হ্যান্ডলারের নিবন্ধন করতে হবে এবং সেখানে কাজ করতে হবে।
এটিয়েন চারল্যান্ড

লেখার পর থেকে আমি এই উত্তরটি ব্যাপকভাবে পরিবর্তন করেছি, পরে উত্পাদনে এটি ব্যবহার করা কিছু সমস্যার সমাধানের সাথে এটি আপডেট করেছি
অ্যাডাম এইচ

এই সমাধানটি দুর্দান্ত, তবে আমি জুমের উত্স হিসাবে মাউস পয়েন্টার অবস্থানটি ব্যবহার না করে কোনও চিত্রকে জুম বা আউট করার সময় কেন মাউস হুইল স্ক্রোল ফাংশনটির এক দিকের দিকে অদ্ভুত টান বলে মনে হচ্ছে তা আমি পুরোপুরি বুঝতে পারি না। আমি কি পাগল নাকি এর জন্য কিছু যৌক্তিক ব্যাখ্যা আছে?
পল কারকোস্কা

আমি এটিকে একটি স্ক্রোলভিউয়ার নিয়ন্ত্রণের মধ্যে নিয়মিত কাজ করার চেষ্টা করার চেষ্টা করছি। আমি স্কেল উত্স হিসাবে মাউস অবস্থানটি (মাউস অবস্থানটি জুম ইন এবং আউট) হিসাবে কসারের অবস্থানটি ব্যবহার করতে কিছুটা সংশোধন করেছি, তবে কীভাবে এটি কোনও স্ক্রোলভিউয়ারের অভ্যন্তরে কাজ করতে যায় সে সম্পর্কে কিছুটা ইনপুট ব্যবহার করতে পারি। ধন্যবাদ!
পল কারকোস্কা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.