[WPF] タッチアプリケーション

[注意]ファイルを適切な場所に保存後、最初にCSSへのパスが適正であるかを確認すること。

[概要を記載します]

 

 

 

1. 初めてののタッチアプリケーションの作成

[概要]

Microsoft ホームページで紹介されている「チュートリアル: 初めてのタッチ アプリケーションの作成 - WPF .NET Framework | Microsoft Learn」を実際に作成して動作確認してみます。

※ 私の都合でオリジナルから若干変更しています。

 

[環境]

コンパイラ : Visual Studio 2022 community, Version 17.10.0
フレームワーク : .NET Framework, 4.8
OS : Windows11 home, 23H2

 

[手順]

1. Visual C# で、BasicManipulation という名前の WPF アプリケーション プロジェクトを作成します。

 

2. MainWindow.XAML の内容を次の XAML に置き換えます。

このマークアップを使用して、Canvas に赤い Rectangle を含む単純なアプリケーションを作成します。
Rectangle の IsManipulationEnabled プロパティは、操作イベントを受け取るために true に設定されています。アプリケーションから、ManipulationStarting、ManipulationDelta、および ManipulationInertiaStarting イベントをサブスクライブします。 これらのイベントには、ユーザーの操作時に Rectangle を移動するロジックが含まれています。

 

["MainWindow.xaml"]

<Window x:Class="BasicManipulation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Move, Size, and Rotate the Square"
        ManipulationStarting="Window_ManipulationStarting"
        ManipulationDelta="Window_ManipulationDelta"
        ManipulationInertiaStarting="Window_InertiaStarting" Width="800" Height="600">
    <Window.Resources>

        <!--The movement, rotation, and size of the Rectangle is 
        specified by its RenderTransform.-->
        <MatrixTransform x:Key="InitialMatrixTransform">
            <MatrixTransform.Matrix>
                <Matrix OffsetX="200" OffsetY="200"/>
            </MatrixTransform.Matrix>
        </MatrixTransform>

    </Window.Resources>

    <Canvas>
        <Rectangle Fill="Red" Name="manRect"
                 Width="200" Height="200" 
                 RenderTransform="{StaticResource InitialMatrixTransform}"
                 IsManipulationEnabled="true" />
    </Canvas>
</Window>

 

NOTE

「IsManupuiationEnable="true"」を指定することで、この Rectangle がタッチ操作の対象であることを設定しています。

 

 

3. 次の ManipulationStarting イベント ハンドラーを MainWindow クラスに追加します。

ManipulationStarting イベントは、タッチ入力によりオブジェクトの操作が始まったことが WPF で検出されたときに発生します。 このコードの場合、ManipulationContainer プロパティを設定することで、操作の位置が Window に対して相対的であることを指定しています。

 

["MainWindow.xaml.cs"]

using System;
using System.Collections.Generic;
using System.Linq;
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 BasicManipulation
{
    /// 
    /// MainWindow.xaml の相互作用ロジック
    /// 
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        void Window_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
        {
            e.ManipulationContainer = this;
            e.Handled = true;
        }
    }
}

 

4. 次の ManipulationDelta イベント ハンドラーを MainWindow クラスに追加します。

 ManipulationDelta イベントは、タッチ入力の位置が変わると発生し、1 回の操作中に複数回発生する可能性があります。このイベントは、指を上げた後にも発生する可能性があります。たとえば、ユーザーが画面上で指をドラッグすると、ManipulationDelta イベントは指の移動時に複数回発生します。 ユーザーが画面から指を上げると、慣性をシミュレートするために ManipulationDelta イベントは発生し続けます。

 このコードでは、ユーザーがタッチ入力を動かすのに合わせて移動されるように DeltaManipulation が Rectangle の RenderTransform に適用されます。 また、慣性の発生中にこのイベントが発生したときに、Rectangle が Window の境界外にあるかどうかも確認されます。 その場合、アプリケーションから ManipulationDeltaEventArgs.Complete メソッドが呼び出され、操作が終了します。

 

["MainWindow.xaml.cs"]

・・・

namespace BasicManipulation
{
    /// 
    /// MainWindow.xaml の相互作用ロジック
    /// 
    public partial class MainWindow : Window
    {
        ・・・

        void Window_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {

            // Get the Rectangle and its RenderTransform matrix.
            Rectangle rectToMove = e.OriginalSource as Rectangle;
            Matrix rectsMatrix = ((MatrixTransform)rectToMove.RenderTransform).Matrix;

            // Rotate the Rectangle.
            rectsMatrix.RotateAt(e.DeltaManipulation.Rotation,
                                 e.ManipulationOrigin.X,
                                 e.ManipulationOrigin.Y);

            // Resize the Rectangle.  Keep it square
            // so use only the X value of Scale.
            rectsMatrix.ScaleAt(e.DeltaManipulation.Scale.X,
                                e.DeltaManipulation.Scale.X,
                                e.ManipulationOrigin.X,
                                e.ManipulationOrigin.Y);

            // Move the Rectangle.
            rectsMatrix.Translate(e.DeltaManipulation.Translation.X,
                                  e.DeltaManipulation.Translation.Y);

            // Apply the changes to the Rectangle.
            rectToMove.RenderTransform = new MatrixTransform(rectsMatrix);

            Rect containingRect =
                new Rect(((FrameworkElement)e.ManipulationContainer).RenderSize);

            Rect shapeBounds =
                rectToMove.RenderTransform.TransformBounds(
                    new Rect(rectToMove.RenderSize));

            // Check if the rectangle is completely in the window.
            // If it is not and intertia is occuring, stop the manipulation.
            if (e.IsInertial && !containingRect.Contains(shapeBounds))
            {
                e.Complete();
            }

            e.Handled = true;
        }
    }
}

 

5. 次の ManipulationInertiaStarting イベント ハンドラーを MainWindow クラスに追加します。

 ManipulationInertiaStarting イベントは、ユーザーが画面からすべての指を上げたときに発生します。このコードにより、四角形の移動、拡大、および回転の初期速度と減速を設定します。

 

["MainWindow.xaml.cs"]

・・・

namespace BasicManipulation
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        ・・・

        void Window_InertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
        {

            // Decrease the velocity of the Rectangle's movement by
            // 10 inches per second every second.
            // (10 inches * 96 pixels per inch / 1000ms^2)
            e.TranslationBehavior.DesiredDeceleration = 10.0 * 96.0 / (1000.0 * 1000.0);

            // Decrease the velocity of the Rectangle's resizing by
            // 0.1 inches per second every second.
            // (0.1 inches * 96 pixels per inch / (1000ms^2)
            e.ExpansionBehavior.DesiredDeceleration = 0.1 * 96 / (1000.0 * 1000.0);

            // Decrease the velocity of the Rectangle's rotation rate by
            // 2 rotations per second every second.
            // (2 * 360 degrees / (1000ms^2)
            e.RotationBehavior.DesiredDeceleration = 720 / (1000.0 * 1000.0);

            e.Handled = true;
        }
    }
}

 

6. プロジェクトをビルドして実行します。ウィンドウに赤い四角形が表示されます。

プログラム実行結果 - ウィンドウ&赤い四角形

 

7. アプリケーションのテスト

アプリケーションをテストするために、次の操作を試します。 次のうち、複数の操作を同時に実行できることに注意してください。

 

最後に全体コードを以下に示します。

 

["MainWindow.xaml.cs"]

using System;
using System.Collections.Generic;
using System.Linq;
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 BasicManipulation
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        void Window_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
        {
            e.ManipulationContainer = this;
            e.Handled = true;
        }

        void Window_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {

            // Get the Rectangle and its RenderTransform matrix.
            Rectangle rectToMove = e.OriginalSource as Rectangle;
            Matrix rectsMatrix = ((MatrixTransform)rectToMove.RenderTransform).Matrix;

            // Rotate the Rectangle.
            rectsMatrix.RotateAt(e.DeltaManipulation.Rotation,
                                 e.ManipulationOrigin.X,
                                 e.ManipulationOrigin.Y);

            // Resize the Rectangle.  Keep it square
            // so use only the X value of Scale.
            rectsMatrix.ScaleAt(e.DeltaManipulation.Scale.X,
                                e.DeltaManipulation.Scale.X,
                                e.ManipulationOrigin.X,
                                e.ManipulationOrigin.Y);

            // Move the Rectangle.
            rectsMatrix.Translate(e.DeltaManipulation.Translation.X,
                                  e.DeltaManipulation.Translation.Y);

            // Apply the changes to the Rectangle.
            rectToMove.RenderTransform = new MatrixTransform(rectsMatrix);

            Rect containingRect =
                new Rect(((FrameworkElement)e.ManipulationContainer).RenderSize);

            Rect shapeBounds =
                rectToMove.RenderTransform.TransformBounds(
                    new Rect(rectToMove.RenderSize));

            // Check if the rectangle is completely in the window.
            // If it is not and intertia is occuring, stop the manipulation.
            if (e.IsInertial && !containingRect.Contains(shapeBounds))
            {
                e.Complete();
            }

            e.Handled = true;
        }

        void Window_InertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
        {

            // Decrease the velocity of the Rectangle's movement by
            // 10 inches per second every second.
            // (10 inches * 96 pixels per inch / 1000ms^2)
            e.TranslationBehavior.DesiredDeceleration = 10.0 * 96.0 / (1000.0 * 1000.0);

            // Decrease the velocity of the Rectangle's resizing by
            // 0.1 inches per second every second.
            // (0.1 inches * 96 pixels per inch / (1000ms^2)
            e.ExpansionBehavior.DesiredDeceleration = 0.1 * 96 / (1000.0 * 1000.0);

            // Decrease the velocity of the Rectangle's rotation rate by
            // 2 rotations per second every second.
            // (2 * 360 degrees / (1000ms^2)
            e.RotationBehavior.DesiredDeceleration = 720 / (1000.0 * 1000.0);

            e.Handled = true;
        }
    }
}

 

 

ライセンス

本ページの情報は、特記無い限り下記 MIT ライセンスで提供されます。

The MIT License (MIT)

  Copyright 2024 Kinoshita Hidetoshi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 

 

参考

 


 

変更履歴

2024-05-23 - 新規作成

 

Programming Items トップページ

プライバシーポリシー