Back to Devexpress

How to: Handle the HyperlinkClick Event to Invoke the Custom Form

wpf-118237-controls-and-libraries-rich-text-editor-examples-automation-how-to-handle-the-hyperlink-click-event-to-invoke-the-custom-form.md

latest12.0 KB
Original Source

How to: Handle the HyperlinkClick Event to Invoke the Custom Form

  • Nov 29, 2023
  • 6 minutes to read

The following example demonstrates how to manually implement complex hyperlink behavior by handling the RichEditControl.HyperlinkClick event. In this example, this event handler is used to invoke a form with the data list. An end-user can select the desired item from the pop-up list. The value of the selected item automatically replaces the hyperlink content.

To accomplish this task, perform the following actions.

  • Create a document with hyperlinks.
  • Implement a custom form depending on your current needs and provide it with the members allowing you to retrieve the selected item value, associate it with the hyperlink and determine the form’s startup location.
  • Handle the main form’s RichEditControl.HyperlinkClick event to invoke the created form. In this event handler, call the SubDocument.Replace method to substitute the hyperlink content with the desired value.

Tip

If you want to change the modifier key used to activate the hyperlink, specify the main form’s DXRichEditHyperlinkOptions.ModifierKeys property. You can select any of the available keys or set the property to None to activate the hyperlink by a click.

The steps below provide more detailed information on how to display a custom pop-up list by clicking a hyperlink.

Custom Form

First, create a custom form with the ListBoxEdit, which will be shown when a hyperlink is clicked. In Visual Studio’s Solution Explorer window, right-click your project and select “Add | User Control…”. Then, open the Toolbox and drop the ListBoxEdit onto the new form.

Create two properties, EditValue and Range. The first property gets the value of the selected list item; the second property is used to refer to the document range which will be replaced with the selected value.

csharp
object fEditValue;
DocumentRange fRange;
public virtual object EditValue {
    get {
        return fEditValue;
    }
}
public DocumentRange Range {
    get {
        return fRange;
    }
    set {
        fRange = value;
    }
}
vb
Private fEditValue As Object
Private fRange As DocumentRange
Public Overridable ReadOnly Property EditValue() As Object
    Get
        Return fEditValue
    End Get
End Property
Public Property Range() As DocumentRange
    Get
        Return fRange
    End Get
    Set(ByVal value As DocumentRange)
        fRange = value
    End Set
End Property

Additionally, add the OwnerWindow property of a FloatingContainer class. This property allows you to set the startup position of a custom form.

csharp
FloatingContainer fOwnerWindow;
public FloatingContainer OwnerWindow {
    get {
        return fOwnerWindow;
    }
    set {
        if (fOwnerWindow == value) return;
        fOwnerWindow = value;
        OnOwnerWindowChanged();
    }
}
protected void OnOwnerWindowChanged() {
    if (OwnerWindow != null)
        OwnerWindow.Caption = "Select a product";
}
vb
Private fOwnerWindow As FloatingContainer
Public Property OwnerWindow() As FloatingContainer
    Get
        Return fOwnerWindow
    End Get
    Set(ByVal value As FloatingContainer)
        If fOwnerWindow Is value Then
            Return
        End If
        fOwnerWindow = value
        OnOwnerWindowChanged()
    End Set
End Property
Protected Sub OnOwnerWindowChanged()
    If OwnerWindow IsNot Nothing Then
        OwnerWindow.Caption = "Select a product"
    End If
End Sub

Declare the Commit event, which is raised when the form is going to be invoked. This event is used to catch the moment when an item is selected from the list.

csharp
EventHandler onCommit;
public event EventHandler Commit { 
    add { onCommit += value; } 
    remove { onCommit -= value; } }
vb
Private onCommit As EventHandler
Public Custom Event Commit As EventHandler
    AddHandler(ByVal value As EventHandler)
        onCommit = DirectCast(System.Delegate.Combine(onCommit, value), EventHandler)
    End AddHandler
    RemoveHandler(ByVal value As EventHandler)
        onCommit = DirectCast(System.Delegate.Remove(onCommit, value), EventHandler)
    End RemoveHandler
    RaiseEvent(ByVal sender As System.Object, ByVal e As System.EventArgs)
        If onCommit IsNot Nothing Then
            For Each d As EventHandler In onCommit.GetInvocationList()
                d.Invoke(sender, e)
            Next d
        End If
    End RaiseEvent
End Event

Main Form

In the main form class, handle the RichEditControl.HyperlinkClick event as shown in the code snippet below.

csharp
private void richEditControl1_HyperlinkClick(object sender, HyperlinkClickEventArgs e)
{
    if (e.ModifierKeys != this.richEditControl1.Options.Hyperlinks.ModifierKeys)
        return;

    //Initialize the custom form            
    SelectProductForm control = new SelectProductForm(products);

    //Subscribe it to the OnCommit event
    control.Commit += OnProductFormCommit;

    //Connect the form with the hyperlink range
    control.Range = e.Hyperlink.Range;

    //Associate the form with the FloatingContainer instance
    FloatingContainer container = FloatingContainerFactory.Create(FloatingMode.Window);

    control.OwnerWindow = container;
    container.Content = control;
    container.Owner = this.richEditControl1;
    ((ILogicalOwner)this.richEditControl1).AddChild(container);

    //Set the form's location and size
    container.SizeToContent = SizeToContent.WidthAndHeight;
    container.ContainerStartupLocation = WindowStartupLocation.Manual;
    container.FloatLocation = GetFormLocation();
    container.IsOpen = true;
    this.activeWindow = container;
    control.Focus();

    e.Handled = true;
}
vb
Private Sub richEditControl1_HyperlinkClick(ByVal sender As Object, ByVal e As HyperlinkClickEventArgs)
    If e.ModifierKeys <> Me.richEditControl1.Options.Hyperlinks.ModifierKeys Then
        Return
    End If

    'Initialize the custom form            
    Dim control As New SelectProductForm(products)

    'Subscribe it to the OnCommit event
    AddHandler control.Commit, AddressOf OnProductFormCommit

    'Connect the form with the hyperlink range
    control.Range = e.Hyperlink.Range

    'Associate the form with the FloatingContainer instance
    Dim container As FloatingContainer = FloatingContainerFactory.Create(FloatingMode.Window)

    control.OwnerWindow = container
    container.Content = control
    container.Owner = Me.richEditControl1
    DirectCast(Me.richEditControl1, ILogicalOwner).AddChild(container)

    'Set the form's location and size
    container.SizeToContent = SizeToContent.WidthAndHeight
    container.ContainerStartupLocation = WindowStartupLocation.Manual
    container.FloatLocation = GetFormLocation()
    container.IsOpen = True
    Me.activeWindow = container
    control.Focus()

    e.Handled = True
End Sub

Implement a method which determines the form’s startup location relative to the caret position (can be accessed using the RichEditControl.GetBoundsFromPosition method).

csharp
System.Windows.Point GetFormLocation()
{
    //Retrieve the caret position
    DocumentPosition position = this.richEditControl1.Document.CaretPosition;
    Rectangle rect = this.richEditControl1.GetBoundsFromPosition(position);

    //Set the startup location relative to the retrieved position
    //within the application bounds
    Rectangle richViewBounds = GetRichEditViewBounds();
    System.Drawing.Point location = new System.Drawing.Point(rect.Right - richViewBounds.X, rect.Bottom - richViewBounds.Y);
    System.Drawing.Point localPoint = Units.DocumentsToPixels(location, this.richEditControl1.DpiX, this.richEditControl1.DpiY);
    return new System.Windows.Point(localPoint.X, localPoint.Y);
}

Rectangle GetRichEditViewBounds()
{
    DocumentLayoutUnitConverter documentLayoutUnitConverter = new DocumentLayoutUnitDocumentConverter(this.richEditControl1.DpiX, this.richEditControl1.DpiY);
    return documentLayoutUnitConverter.LayoutUnitsToDocuments(richEditControl1.ViewBounds);
}
vb
Private Function GetFormLocation() As System.Windows.Point
    'Retrieve the caret position
    Dim position As DocumentPosition = Me.richEditControl1.Document.CaretPosition
    Dim rect As Rectangle = Me.richEditControl1.GetBoundsFromPosition(position)

    'Set the startup location relative to the retrieved position
    'within the application bounds
    Dim richViewBounds As Rectangle = GetRichEditViewBounds()
    Dim location As New System.Drawing.Point(rect.Right - richViewBounds.X, rect.Bottom - richViewBounds.Y)
    Dim localPoint As System.Drawing.Point = Units.DocumentsToPixels(location, Me.richEditControl1.DpiX, Me.richEditControl1.DpiY)
    Return New System.Windows.Point(localPoint.X, localPoint.Y)
End Function

Private Function GetRichEditViewBounds() As Rectangle
    Dim documentLayoutUnitConverter As DocumentLayoutUnitConverter = New DocumentLayoutUnitDocumentConverter(Me.richEditControl1.DpiX, Me.richEditControl1.DpiY)
    Return documentLayoutUnitConverter.LayoutUnitsToDocuments(richEditControl1.ViewBounds)
End Function

Finally, declare the Commit event handler as follows.

csharp
void OnProductFormCommit(object sender, EventArgs e)
{
    SelectProductForm form = (SelectProductForm)sender;

    //Retrieve the selected item value
    string value = (string)form.EditValue;
    Document document = this.richEditControl1.Document;

    //Start the document modification
    document.BeginUpdate();

    //Replace the hyperlink range content
    //with the retrieved value
    document.Replace(form.Range, value);

    //Finish the document update
    document.EndUpdate();
}
vb
Private Sub OnProductFormCommit(ByVal sender As Object, ByVal e As EventArgs)
    Dim form As SelectProductForm = DirectCast(sender, SelectProductForm)

    'Retrieve the selected item value
    Dim value As String = DirectCast(form.EditValue, String)
    Dim document As Document = Me.richEditControl1.Document

    'Start the document modification
    document.BeginUpdate()

    'Replace the hyperlink range content
    'with the retireved value
    document.Replace(form.Range, value)

    'Finish the document update
    document.EndUpdate()
End Sub