Add Adorner to Image in WPF RichTextBox when loaded

1.5k Views Asked by At

I have a RichTextBox control in an application I am developing which I am using along with a ToolBar to create a rich text editor. One feature I have implemented is the ability for a user to insert an Image, now it worth noting at this point that the output from the RichTextBox is RTF.

When the user inserts the Image I am using the following code to add the image to the Document and then add a ResizeAdorner (example from here RichTextBox Resizing Adorner) to the Image which allows the user to resize. When the user saves and loads the Document the size of the Image is persisted correctly.

private void BtnInsertImage_OnClick(object sender, RoutedEventArgs e)
{
    OpenFileDialog ofd = new OpenFileDialog();
    ofd.Multiselect = false;
    ofd.CheckFileExists = true;
    ofd.CheckPathExists = true;
    ofd.Filter = "Image files (*.png;*.jpg;*.jpeg;*.gif;*.bmp)|*.png;*.jpg;*.jpeg;*.gif;*.bmp";
    ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
    ofd.Title = "Insert Image";
    if (ofd.ShowDialog() == true)
    {
        BitmapImage bitmap = new BitmapImage(new Uri(ofd.FileName, UriKind.RelativeOrAbsolute))
                                 {
                                     CacheOption = BitmapCacheOption.OnLoad
                                 };
        Image image = new Image();
        image.IsEnabled = true;
        image.Source = bitmap;
        image.Width = bitmap.Width;
        image.Height = bitmap.Height;
        image.Loaded += this.ImageOnLoaded;
        image.Stretch = Stretch.Uniform;

        InlineUIContainer container = new InlineUIContainer(image, this.rtbEditor.Selection.Start);
        Paragraph paragraph = new Paragraph(container);

        var doc = this.rtbEditor.Document;
        doc.Blocks.Add(paragraph);
    }
}

private void ImageOnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
    var img = sender as Image;
    if (img != null)
    {
        var al = AdornerLayer.GetAdornerLayer(img);
        if (al != null)
        {
            al.Add(new ResizingAdorner(img));
        }
    }
}

The problem and question is that when the Document is loaded i am unable to figure out how to add the ResizingAdorner to the Images in the document. I am using an attached property to load the document contents, the code below is the part that loads the document:

var stream = new MemoryStream(Encoding.UTF8.GetBytes(GetDocumentXaml(richTextBox)));
var doc = new FlowDocument();
var range = new TextRange(doc.ContentStart, doc.ContentEnd);

range.Load(stream, DataFormats.Xaml);

richTextBox.Document = doc;

Could anyone help with how I can add the ResizingAdorner to any images in the loaded Document please?

1

There are 1 best solutions below

0
On

So I have worked out a way that I can add the Adorner to the Image in the Document through the SelectionChanged event handler and the following code

var inline = this.rtbEditor.CaretPosition.GetAdjacentElement(LogicalDirection.Forward) as Inline;
if (inline != null)
{
    this.AddAdorner(inline.NextInline as InlineUIContainer);
    this.AddAdorner(inline.PreviousInline as InlineUIContainer);
}

And this is the AddAdorner method

private void AddAdorner(InlineUIContainer container)
{
    if (container != null)
    {
        var image = container.Child;
        if (image != null)
        {
            var al = AdornerLayer.GetAdornerLayer(image);
            if (al != null)
            {
                var currentAdorners = al.GetAdorners(image);
                if (currentAdorners != null)
                {
                    foreach (var adorner in currentAdorners)
                    {
                        al.Remove(adorner);
                    }
                }

                al.Add(new ResizingAdorner(image));
            }
        }
    }
}

I know this is probably not the most elegant way to achieve this but for me this works so I wanted to post this so that others can choose to use this if appropriate