InkCanvas Z-order support  
Author Message
borice





PostPosted: Notebook, Tablet PC, and UMPC Development, InkCanvas Z-order support Top

Hello,

Is it possible to implement Z-order functionality with *ink and objects* in InkCanvas

Specifically be able to have, for example (from lowest layer to highest layer):

a. a text box

b. some ink overlapping the text box

c. some shape overlapping (b)

etc...

From what I've seen, "ink" in an InkCanvas is always rendered "on top". What would be involved in creating this functionality

Thank you,

Boris



Software Development for Windows Vista5  
 
 
Stefan Wick - MSFT





PostPosted: Notebook, Tablet PC, and UMPC Development, InkCanvas Z-order support Top

Hi Boris,

here is how the z-order funtionality works for ink and elements in InkCanvas works:

1) the z-order of elements relative to each other can be controlled by setting the Panel.ZIndex property on the element

2) Ink is always rendered on top of InkCanvas's child elements

3) If you want elements to be rendered on top of the ink, you have two choices:

a) make the element a sibling of InkCanvas with a higher Panel.ZIndex

b) render the element in InkCanvas's AdornerLayer (which is always on top of the ink)

Please let me know if you have more questions about this.

Thanks, Stefan Wick



 
 
borice





PostPosted: Notebook, Tablet PC, and UMPC Development, InkCanvas Z-order support Top

Stefan - thanks for your answer.

None of these options seems to provide the type of functionality I was looking for. Basically I wanted to be able to have a child element of InkCanvas (like a textbox), sandwiched between ink strokes. In other words I want to have a fine granularity in controling who goes on top of what... seems like the only thing that will get me there is to implement my own InkCavas from the building blocks provided (InkPresenter, DynamicRenderer..etc)

I'm looking into creating a "layered" InkCanvas, functioning in a similar way to how layers work in Adobe Photoshop (if you're familiar with that). Among the requirements would be to be able to reorder these layers (decide the z-index of each layer), and maybe even within each layer decide the z-index of the containing elements (ink and rest).

If you have any other advice to get me closer to this goal, I'm all ears :-)

Thank you!

Boris


 
 
Stefan Wick - MSFT





PostPosted: Notebook, Tablet PC, and UMPC Development, InkCanvas Z-order support Top

Hi Boris,

if I understand you correctly you basically want to assign a different z-order to different subsets of your ink strokes. For that you would need one InkPresenter (or InkCanvas which is built on top of InkPresenter) for each layer of ink.

You go could down the route of creating your own control with multiple InkPresenters, but you might be able to accomplish what you want by layering a bunch on InkCanvas elements on top of each other.

As a starting point, here is a simple user control that can host ink and elements in different levels and allows you to move them between the levels:

XAML:

<UserControl x:Class="WindowsApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Name="mainCanvas">
<InkCanvas Name="lowerLayer" Width="{Binding ElementName=mainCanvas,Path=ActualWidth}"
Height="{Binding ElementName=mainCanvas,Path=ActualHeight}"
Background="Yellow" StrokeCollected="OnStroke" StrokeErasing="OnStrokeErasing"/>
<InkCanvas Name="upperLayer" Width="{Binding ElementName=mainCanvas,Path=ActualWidth}"
Height="{Binding ElementName=mainCanvas,Path=ActualHeight}"
Background="Transparent" IsHitTestVisible="False" EditingMode="None" />
</Canvas>
</UserControl>

C# code behind to manage the layers of ink and elements:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Ink;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace WindowsApplication1
{
public partial class UserControl1 : System.Windows.Controls.UserControl
{
private StrokeCollection _strokes = new StrokeCollection();

public UserControl1()
{
InitializeComponent();
}

private void OnStroke(object sender, InkCanvasStrokeCollectedEventArgs e)
{
_strokes.Add(e.Stroke);
}

private void OnStrokeErasing(object sender, InkCanvasStrokeErasingEventArgs e)
{
_strokes.Remove(e.Stroke);
}

public StrokeCollection Strokes
{
get { return _strokes; }
}

public void AddElementBehindInk(UIElement element)
{
lowerLayer.Children.Add(element);
}

public void AddElementOnTop(UIElement element)
{
upperLayer.Children.Add(element);
}

public void MoveElementBehind(UIElement element)
{
if (upperLayer.Children.Contains(element))
{
upperLayer.Children.Remove(element);
lowerLayer.Children.Add(element);
}
}

public void MoveElementOnTop(UIElement element)
{
if (lowerLayer.Children.Contains(element))
{
lowerLayer.Children.Remove(element);
upperLayer.Children.Add(element);
}
}

public void MoveStrokeOnTop(Stroke stroke)
{
if (lowerLayer.Strokes.Contains(stroke))
{
lowerLayer.Strokes.Remove(stroke);
upperLayer.Strokes.Add(stroke);
}
}

public void MoveStrokeBehind(Stroke stroke)
{
if (upperLayer.Strokes.Contains(stroke))
{
upperLayer.Strokes.Remove(stroke);
lowerLayer.Strokes.Add(stroke);
}
}
}
}

Thanks, Stefan Wick