コンポジションのビジュアルComposition visual

コンポジションのビジュアル オブジェクト ツリー構造は、コンポジション API の他のすべての機能でベースとして使われます。Composition Visuals make up the visual tree structure which all other features of the composition API use and build on. この API により、開発者は 1 つまたは複数のビジュアル オブジェクトを作成して定義できます。それぞれがビジュアル オブジェクト ツリーの 1 つのノードを表します。The API allows developers to define and create one or many visual objects each representing a single node in a visual tree.

ビジュアル オブジェクトVisuals

ビジュアル オブジェクト ツリー構造には、3 種類のビジュアル オブジェクトが含まれ、加えて、ビジュアル オブジェクトの内容に影響を与える基本ブラシ クラスと複数のサブクラスがあります。There are three visual types that make up the visual tree structure plus a base brush class with multiple subclasses that affect the content of a visual:

  • Visual – 基本オブジェクトのプロパティの大半はこことその他のビジュアル オブジェクトに継承します。Visual – base object, the majority of the properties are here, and inherited by the other Visual objects.
  • ContainerVisual – から派生した Visual子を作成する機能を追加します。ContainerVisual – derives from Visual, and adds the ability to create children.
  • SpriteVisual – から派生した ContainerVisual 関連付けにブラシ効果のイメージを含めピクセルのビジュアルをレンダリングできるようにしたり、信頼性の高い機能を追加します。色。SpriteVisual – derives from ContainerVisual and adds the ability to associate a brush so that the Visual can render pixels including images, effects or a solid color.

CompositionBrush とそのサブクラスである CompositionColorBrushCompositionSurfaceBrushCompositionEffectBrush を使用して、コンテンツと効果を SpriteVisual に適用できます。You can apply content and effects to SpriteVisuals using the CompositionBrush and its subclasses including the CompositionColorBrush, CompositionSurfaceBrush and CompositionEffectBrush. ブラシについて詳しくは、「CompositionBrush の概要」をご覧ください。To learn more about brushes see our CompositionBrush Overview.

CompositionVisual のサンプルThe CompositionVisual Sample

ここでは、前に説明した 3 つの種類のビジュアル タイプを使用する、いくつかのサンプル コードについて説明します。Here, we'll look at some sample code that demonstrates the three different visual types listed previously. このサンプルでは、アニメーションや複雑な効果のような概念は取り上げていませんが、それらのシステムで使われるビルディング ブロックは含まれています。While this sample doesn’t cover concepts like Animations or more complex effects, it contains the building blocks that all of those systems use. (完全なサンプル コードは、この記事の最後に示されています。)(The full sample code is listed at the end of this article.)

このサンプルでは、画面でクリックしてドラッグできる複数の単色の正方形を使います。In the sample are a number of solid color squares that can be clicked on and dragged about the screen. 正方形がクリックされると、前面に移動して 45 度回転し、ドラッグされると不透明になります。When a square is clicked on, it will come to the front, rotate 45 degrees, and become opaque when dragged about.

ここでは、次のように API の操作について多数の基本的な概念を示します。This shows a number of basic concepts for working with the API including:

  • コンポジターの作成Creating a compositor
  • SpriteVisual と CompositionColorBrush の作成Creating a SpriteVisual with a CompositionColorBrush
  • ビジュアル オブジェクトのクリッピングClipping the Visual
  • ビジュアル オブジェクトの回転Rotating the Visual
  • 不透明度の設定Setting Opacity
  • コレクション内のビジュアル オブジェクトの位置変更Changing the Visual’s position in the collection.

コンポジターの作成Creating a Compositor

Compositor を作成し、ファクトリ用に変数に格納するのは簡単です。Creating a Compositor and storing it in a variable for use as a factory is a simple task. 次のスニペットでは、新しい Compositor の作成方法を示しています。The following snippet shows creating a new Compositor:

_compositor = new Compositor();

SpriteVisual と ColorBrush の作成Creating a SpriteVisual and ColorBrush

Compositor を使って、必要なときにオブジェクト、たとえば SpriteVisualCompositionColorBrush を作成するのは簡単です。Using the Compositor it's easy to create objects whenever you need them, such as a SpriteVisual and a CompositionColorBrush:

var visual = _compositor.CreateSpriteVisual();
visual.Brush = _compositor.CreateColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));

これは、数行のコードのみですが、強力な概念を示します。SpriteVisual オブジェクトが、効果のシステムの中核です。While this is only a few lines of code, it demonstrates a powerful concept: SpriteVisual objects are the heart of the effects system. SpriteVisual を使うと、色、画像、効果の作成で高い柔軟性と関係性を得られます。The SpriteVisual allows for great flexibility and interplay in color, image and effect creation. SpriteVisual は、ブラシで (この例では単色) で 2D 四角形を塗りつぶすことのできるビジュアル オブジェクトの一種です。The SpriteVisual is a single visual type that can fill a 2D rectangle with a brush, in this case, a solid color.

ビジュアル オブジェクトのクリップClipping a Visual

Compositor は、Visual に対するクリップを作成するためにも使えます。The Compositor can also be used to create clips to a Visual. 次に示しているのは、ビジュアル オブジェクトの両側をトリミングする InsetClip を使ったサンプルからの例です。Below is an example from the sample of using the InsetClip to trim each side of the visual:

var clip = _compositor.CreateInsetClip();
clip.LeftInset = 1.0f;
clip.RightInset = 1.0f;
clip.TopInset = 1.0f;
clip.BottomInset = 1.0f;
_currentVisual.Clip = clip;

API の他のオブジェクトと同様、InsetClip のプロパティにもアニメーションを適用できます。Like other objects in the API, InsetClip can have animations applied to its properties.

画像を回転Rotating a Clip

Visual は回転により変換できます。A Visual can be transformed with a rotation. RotationAngle では、ラジアンと度の両方がサポートされています。Note that RotationAngle supports both radians and degrees. 既定ではラジアンになりますが、次のコードに示しているように、度を指定するのは簡単です。It defaults to radians, but it’s easy to specify degrees as shown in the following snippet:

child.RotationAngleInDegrees = 45.0f;

Rotation は、変換が簡単になるように API に用意された一連の変換コンポーネントのほんの一例です。Rotation is just one example of a set of transform components provided by the API to make these tasks easier. そのほかにも Offset、Scale、Orientation、RotationAxis、4x4 TransformMatrix などがあります。Others include Offset, Scale, Orientation, RotationAxis, and 4x4 TransformMatrix.

不透明度の設定Setting Opacity

ビジュアル オブジェクトの不透明度の設定も簡単で、浮動小数値を使って指定するだけです。Setting the opacity of a visual is a simple operation using a float value. たとえば、このサンプルでは、すべての正方形の不透明度は .8 から始めています。For example, in the sample all the squares start at .8 opacity:

visual.Opacity = 0.8f;

Rotation と同様、Opacity のプロパティにもアニメーションを適用できます。Like rotation, the Opacity property can be animated.

コレクション内のビジュアル オブジェクトの位置変更Changing the Visual's position in the collection

コンポジション API を使うと、VisualCollection でのビジュアルの位置を多くの方法で変更できます。The Composition API allows for a Visual's position in a VisualCollection to be changed in a number of ways. たとえば、InsertAbove を使うと、別のビジュアルの上に、InsertBelow を使うと、下に配置できます。InsertAtTop を使うと、先頭に、InsertAtBottom を使うと、末尾に移動できます。It can be placed above another Visual with InsertAbove, placed below with InsertBelow, moved to the top with InsertAtTop, or the bottom with InsertAtBottom.

このサンプルでは、クリックされた Visual は先頭に並べ替えられています。In the sample, a Visual that has been clicked is sorted to the top:

parent.Children.InsertAtTop(_currentVisual);

完全な例Full Example

完全なサンプルでは、これまで説明した概念のすべてを一緒に使って、Visual オブジェクトの単純なツリーを作成してたどり、XAML、WWA、または DirectX を使わずに不透明度を変更しています。In the full sample, all of the concepts above are used together to construct and walk a simple tree of Visual objects to change opacity without using XAML, WWA, or DirectX. このサンプルでは、どのように子 Visual オブジェクトが作成されて追加され、プロパティが変更されるかを示しています。This sample shows how child Visual objects are created and added and how properties are changed.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Composition;
using Windows.UI.Core;

namespace compositionvisual
{
    class VisualProperties : IFrameworkView
    {
        //------------------------------------------------------------------------------
        //
        // VisualProperties.Initialize
        //
        // This method is called during startup to associate the IFrameworkView with the
        // CoreApplicationView.
        //
        //------------------------------------------------------------------------------

        void IFrameworkView.Initialize(CoreApplicationView view)
        {
            _view = view;
            _random = new Random();
        }

        //------------------------------------------------------------------------------
        //
        // VisualProperties.SetWindow
        //
        // This method is called when the CoreApplication has created a new CoreWindow,
        // allowing the application to configure the window and start producing content
        // to display.
        //
        //------------------------------------------------------------------------------

        void IFrameworkView.SetWindow(CoreWindow window)
        {
            _window = window;
            InitNewComposition();
            _window.PointerPressed += OnPointerPressed;
            _window.PointerMoved += OnPointerMoved;
            _window.PointerReleased += OnPointerReleased;
        }

        //------------------------------------------------------------------------------
        //
        // VisualProperties.OnPointerPressed
        //
        // This method is called when the user touches the screen, taps it with a stylus
        // or clicks the mouse.
        //
        //------------------------------------------------------------------------------

        void OnPointerPressed(CoreWindow window, PointerEventArgs args)
        {
            Point position = args.CurrentPoint.Position;

            //
            // Walk our list of visuals to determine who, if anybody, was selected
            //
            foreach (var child in _root.Children)
            {
                //
                // Did we hit this child?
                //
                Vector3 offset = child.Offset;
                Vector2 size = child.Size;

                if ((position.X >= offset.X) &&
                    (position.X < offset.X + size.X) &&
                    (position.Y >= offset.Y) &&
                    (position.Y < offset.Y + size.Y))
                {
                    //
                    // This child was hit. Since the children are stored back to front,
                    // the last one hit is the front-most one so it wins
                    //
                    _currentVisual = child as ContainerVisual;
                    _offsetBias = new Vector2((float)(offset.X - position.X),
                                              (float)(offset.Y - position.Y));
                }
            }

            //
            // If a visual was hit, bring it to the front of the Z order
            //
            if (_currentVisual != null)
            {
                ContainerVisual parent = _currentVisual.Parent as ContainerVisual;
                parent.Children.Remove(_currentVisual);
                parent.Children.InsertAtTop(_currentVisual);
            }
        }

        //------------------------------------------------------------------------------
        //
        // VisualProperties.OnPointerMoved
        //
        // This method is called when the user moves their finger, stylus or mouse with
        // a button pressed over the screen.
        //
        //------------------------------------------------------------------------------

        void OnPointerMoved(CoreWindow window, PointerEventArgs args)
        {
            //
            // If a visual is selected, drag it with the pointer position and
            // make it opaque while we drag it
            //
            if (_currentVisual != null)
            {
                //
                // Set up the properties of the visual the first time it is
                // dragged. This will last for the duration of the drag
                //
                if (!_dragging)
                {
                    _currentVisual.Opacity = 1.0f;

                    //
                    // Transform the first child of the current visual so that
                    // the image is rotated
                    //
                    foreach (var child in _currentVisual.Children)
                    {
                        child.RotationAngleInDegrees = 45.0f;
                        child.CenterPoint = new Vector3(_currentVisual.Size.X / 2, _currentVisual.Size.Y / 2, 0);
                        break;
                    }

                    //
                    // Clip the visual to its original layout rect by using an inset
                    // clip with a one-pixel margin all around
                    //
                    var clip = _compositor.CreateInsetClip();
                    clip.LeftInset = 1.0f;
                    clip.RightInset = 1.0f;
                    clip.TopInset = 1.0f;
                    clip.BottomInset = 1.0f;
                    _currentVisual.Clip = clip;

                    _dragging = true;
                }

                Point position = args.CurrentPoint.Position;
                _currentVisual.Offset = new Vector3((float)(position.X + _offsetBias.X),
                                                    (float)(position.Y + _offsetBias.Y),
                                                    0.0f);
            }
        }

        //------------------------------------------------------------------------------
        //
        // VisualProperties.OnPointerReleased
        //
        // This method is called when the user lifts their finger or stylus from the
        // screen, or lifts the mouse button.
        //
        //------------------------------------------------------------------------------

        void OnPointerReleased(CoreWindow window, PointerEventArgs args)
        {
            //
            // If a visual was selected, make it transparent again when it is
            // released and restore the transform and clip
            //
            if (_currentVisual != null)
            {
                if (_dragging)
                {
                    //
                    // Remove the transform from the first child
                    //
                    foreach (var child in _currentVisual.Children)
                    {
                        child.RotationAngle = 0.0f;
                        child.CenterPoint = new Vector3(0.0f, 0.0f, 0.0f);
                        break;
                    }

                    _currentVisual.Opacity = 0.8f;
                    _currentVisual.Clip = null;
                    _dragging = false;
                }

                _currentVisual = null;
            }
        }

        //------------------------------------------------------------------------------
        //
        // VisualProperties.Load
        //
        // This method is called when a specific page is being loaded in the
        // application.  It is not used for this application.
        //
        //------------------------------------------------------------------------------

        void IFrameworkView.Load(string unused)
        {

        }

        //------------------------------------------------------------------------------
        //
        // VisualProperties.Run
        //
        // This method is called by CoreApplication.Run() to actually run the
        // dispatcher's message pump.
        //
        //------------------------------------------------------------------------------

        void IFrameworkView.Run()
        {
            _window.Activate();
            _window.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessUntilQuit);
        }

        //------------------------------------------------------------------------------
        //
        // VisualProperties.Uninitialize
        //
        // This method is called during shutdown to disconnect the CoreApplicationView,
        // and CoreWindow from the IFrameworkView.
        //
        //------------------------------------------------------------------------------

        void IFrameworkView.Uninitialize()
        {
            _window = null;
            _view = null;
        }

        //------------------------------------------------------------------------------
        //
        // VisualProperties.InitNewComposition
        //
        // This method is called by SetWindow(), where we initialize Composition after
        // the CoreWindow has been created.
        //
        //------------------------------------------------------------------------------

        void InitNewComposition()
        {
            //
            // Set up Windows.UI.Composition Compositor, root ContainerVisual, and associate with
            // the CoreWindow.
            //

            _compositor = new Compositor();

            _root = _compositor.CreateContainerVisual();



            _compositionTarget = _compositor.CreateTargetForCurrentView();
            _compositionTarget.Root = _root;

            //
            // Create a few visuals for our window
            //
            for (int index = 0; index < 20; index++)
            {
                _root.Children.InsertAtTop(CreateChildElement());
            }
        }

        //------------------------------------------------------------------------------
        //
        // VisualProperties.CreateChildElement
        //
        // Creates a small sub-tree to represent a visible element in our application.
        //
        //------------------------------------------------------------------------------

        Visual CreateChildElement()
        {
            //
            // Each element consists of three visuals, which produce the appearance
            // of a framed rectangle
            //
            var element = _compositor.CreateContainerVisual();
            element.Size = new Vector2(100.0f, 100.0f);

            //
            // Position this visual randomly within our window
            //
            element.Offset = new Vector3((float)(_random.NextDouble() * 400), (float)(_random.NextDouble() * 400), 0.0f);

            //
            // The outer rectangle is always white
            //
            //Note to preview API users - SpriteVisual and Color Brush replace SolidColorVisual
            //for example instead of doing
            //var visual = _compositor.CreateSolidColorVisual() and
            //visual.Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
            //we now use the below

            var visual = _compositor.CreateSpriteVisual();
            element.Children.InsertAtTop(visual);
            visual.Brush = _compositor.CreateColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
            visual.Size = new Vector2(100.0f, 100.0f);

            //
            // The inner rectangle is inset from the outer by three pixels all around
            //
            var child = _compositor.CreateSpriteVisual();
            visual.Children.InsertAtTop(child);
            child.Offset = new Vector3(3.0f, 3.0f, 0.0f);
            child.Size = new Vector2(94.0f, 94.0f);

            //
            // Pick a random color for every rectangle
            //
            byte red = (byte)(0xFF * (0.2f + (_random.NextDouble() / 0.8f)));
            byte green = (byte)(0xFF * (0.2f + (_random.NextDouble() / 0.8f)));
            byte blue = (byte)(0xFF * (0.2f + (_random.NextDouble() / 0.8f)));
            child.Brush = _compositor.CreateColorBrush(Color.FromArgb(0xFF, red, green, blue));

            //
            // Make the subtree root visual partially transparent. This will cause each visual in the subtree
            // to render partially transparent, since a visual's opacity is multiplied with its parent's
            // opacity
            //
            element.Opacity = 0.8f;

            return element;
        }

        // CoreWindow / CoreApplicationView
        private CoreWindow _window;
        private CoreApplicationView _view;

        // Windows.UI.Composition
        private Compositor _compositor;
        private CompositionTarget _compositionTarget;
        private ContainerVisual _root;
        private ContainerVisual _currentVisual;
        private Vector2 _offsetBias;
        private bool _dragging;

        // Helpers
        private Random _random;
    }


    public sealed class VisualPropertiesFactory : IFrameworkViewSource
    {
        //------------------------------------------------------------------------------
        //
        // VisualPropertiesFactory.CreateView
        //
        // This method is called by CoreApplication to provide a new IFrameworkView for
        // a CoreWindow that is being created.
        //
        //------------------------------------------------------------------------------

        IFrameworkView IFrameworkViewSource.CreateView()
        {
            return new VisualProperties();
        }


        //------------------------------------------------------------------------------
        //
        // main
        //
        //------------------------------------------------------------------------------

        static int Main(string[] args)
        {
            CoreApplication.Run(new VisualPropertiesFactory());

            return 0;
        }
    }
}