Search code examples
c#wpfitemscontrolinkcanvas

Multiple InkCanvas instances in ItemsControl -> MousePress on other instance results in long line


I have a problem when using multiple InkCanvas instances within an ItemsControl. Each InkCanvas instance receives an ImageBrush as Background and then is added to the ItemsControl. Basically this is a self written PdfViewer where users can draw remarks etc on the PdfPages and then save the file as pdf again. The original pdf is read, pages are converted to bitmaps and each bitmap is used as background for an InkCanvas.

This works well as long as I don´t click on another canvas. Here are two images to illustrate the problem:

Initial MouseClick

enter image description here

XAML of PdfViewer:

<UserControl x:Class="PdfTool.Code.Controls.PdfViewer"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:viewModel="clr-namespace:PdfTool.Code.ViewModel"
             mc:Ignorable="d" 
             d:DataContext="{d:DesignInstance {x:Type viewModel:CanvasViewModel}, IsDesignTimeCreatable=False}"
             d:DesignHeight="450" d:DesignWidth="800">
    <ScrollViewer PanningMode="Both" Background="{StaticResource MainBackgroundColor}">
        <ItemsControl x:Name="PagesContainer" MouseWheel="PagesContainer_OnMouseWheel">
            <ItemsControl.RenderTransform>
                <MatrixTransform/>
            </ItemsControl.RenderTransform>
        </ItemsControl>
    </ScrollViewer>
</UserControl>

Code behind:

public partial class PdfViewer : UserControl
{
    #region Bindable Properties
    ...
    #endregion

    public PdfViewer()
    {
        InitializeComponent();
    }

    private static async Task PdfToImages(PdfViewer pdfViewer, PdfDocument pdfDoc)
    {
        pdfViewer.Dispatcher.Invoke(() => pdfViewer.PagesContainer.Items.Clear());
        if (pdfDoc == null) return;

        for (uint i = 0; i < pdfDoc.PageCount; i++) {
            using (var page = pdfDoc.GetPage(i)) {
                await pdfViewer.Dispatcher.Invoke(async () =>
                {
                    var bitmap = await PageToBitmapAsync(page);
                    pdfViewer.PagesContainer.Items.Add(new PdfDetailElement(new ImageBrush(bitmap) {Stretch = Stretch.Uniform}));
                });
            }
        }
    }

    ...
}

XAML of a Single PdfPage:

<UserControl x:Class="PdfTool.Code.Controls.PdfDetailElement"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:viewModel="clr-namespace:PdfTool.Code.ViewModel"
             mc:Ignorable="d" 
             d:DataContext="{d:DesignInstance {x:Type viewModel:CanvasViewModel}, IsDesignTimeCreatable=False}"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid Margin="10,10,5,10">
        <Viewbox Stretch="Fill">
            <InkCanvas x:Name="inkCanvas" 
                       Background="{x:Null}" 
                       DefaultDrawingAttributes="{Binding SelectedDrawingAttributes}" 
                       EditingMode="{Binding SelectedEditingMode, UpdateSourceTrigger=PropertyChanged}"/>
        </Viewbox>
    </Grid>
</UserControl>

Code behind:

public partial class PdfDetailElement : UserControl
{
    public PdfDetailElement()
    {
        InitializeComponent();
    }

    public PdfDetailElement(ImageBrush image)
    {
        DataContext = Gui.Main.CanvasSettings;
        InitializeComponent();
        inkCanvas.Background = image;
        inkCanvas.Width = image.ImageSource.Width;
        inkCanvas.Height = image.ImageSource.Height;
    }
}

Only the MouseWheel event is used for Zooming and it is not the cause of the issue. It seems, the coordinates of the mouse on InkCanvas 1 are used as initial value for InkCanvas 2. How can I change this behaviour?


Solution

  • I got it: Stop WPF ScrollViewer automatically scrolling to perceived content got me in the right direction. I simply had to set

    Focusable="False"
    

    on the InkCanvas and my problem is solved, as the RequestBringIntoView event of the Scrollbar is not fired if the object to bring into view is not focusable...