Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

GotFocus events on controls within a RichTextBox FlowDocument

Posted on 2011-04-27
15
Medium Priority
?
1,288 Views
Last Modified: 2013-11-12
hi guys,

i have a FlowDoc within a RTB which i create and manage via code (no xaml). i have multiple blocks within my document, some of which contain Table objects with multiple TableCell objects. I desperately require to have GotFocus and LostFocus events fire from my TableCell and Block objects, however for whatever reason i just cant seem to make it work.

as both objects are created dynamically, i've resorted to the following:
    Dim currentRow As TableRow = New TableRow()
    For i As Integer = 1 To numberOfCols
      Dim cell As New TableCell(New Paragraph(New Run("")))
      currentRow.Cells.Add(cell)
      LoadStyles(cell)
      AddHandler cell.GotFocus, AddressOf ConvertToCurrency
    Next

Open in new window

...where ConvertToCurrency is my method i need called when GotFocus is fired. my RTB itself has its IsDocumentEnabled value set to true.

so what am i missing? any help would be greatly appreciated.

cheers
0
Comment
Question by:gem56
  • 8
  • 7
15 Comments
 
LVL 96

Expert Comment

by:Bob Learned
ID: 35484267
What that sounds like is that the TableCell is not what the RichTextBox sets focus on...did you try to check with the Paragraph or Run?
0
 

Author Comment

by:gem56
ID: 35488460
hello TheLearnedOne, thanks for your reply.

i initially assumed something similar as i read something about focus functions getting an overhaul in wpf, unfortunately it doesnt look like thats exactly it. i've added handlers to the GotFocus events for everything starting at the Run and to every control all the way up to the RTB. it looks like only the rtb itself will fire the gotfocus event.

interestingly enough i can get the TableCell's to fire on MouseEnter events, so i dont think its a matter of controls within the rtb not being able to fire...it just doesnt fire on GotFocus for whatever reason.

any ideas?
cheers
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 35488613
Oh yeah, focus is a lot trickier with WPF that it ever was with Windows Forms, but there is a lot more going on under the hood.  There is a the concept of keyboard focus and mouse focus, focus scopes, etc..  The behavior of the focus changes when the mouse is captured.  The TextBoxBase class creates challenges that are tough to overcome.

Here is an article that talks about one such scenario:

Why is focus in WPF so tricky? [managing and understanding focus in a WPF application]
http://www.pluralsight-training.net/community/blogs/eburke/archive/2009/03/18/why-is-focus-in-wpf-so-tricky-managing-and-understanding-focus-in-a-wpf-application.aspx

You can use the MouseDown event for a Run, and it works:


Imports System.Windows
Imports System.Windows.Documents
Imports System.Windows.Input

	''' <summary>
	''' Interaction logic for MainWindow.xaml
	''' </summary>
	Public Partial Class MainWindow
		Inherits Window
		Public Sub New()
			InitializeComponent()
		End Sub

		Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
			Dim document As New FlowDocument()
			document.Focusable = True

			Dim table As New Table()

			Dim rowGroup As New TableRowGroup()

			table.RowGroups.Add(rowGroup)

			Dim row As New TableRow()

			rowGroup.Rows.Add(row)

			Dim cell As New TableCell()

			row.Cells.Add(cell)

			Dim paragraph As New Paragraph()

			Dim run As New Run()
			run.MouseDown += New MouseButtonEventHandler(AddressOf run_MouseDown)

			run.Text = "This is a test of the radio broadcast system"

			paragraph.Inlines.Add(run)

			cell.Blocks.Add(paragraph)

			document.Blocks.Add(table)

			Me.richTextBox1.Document = document
		End Sub

		Private Sub run_MouseDown(sender As Object, e As MouseButtonEventArgs)
			Dim run As Run = TryCast(sender, Run)
			MessageBox.Show(run.Text)
		End Sub

	End Class

Open in new window

0
Configuration Guide and Best Practices

Read the guide to learn how to orchestrate Data ONTAP, create application-consistent backups and enable fast recovery from NetApp storage snapshots. Version 9.5 also contains performance and scalability enhancements to meet the needs of the largest enterprise environments.

 

Author Comment

by:gem56
ID: 35488792
hello again TheLearnedOne,

thanks for the link but i've already read that page a couple of times now over the last week while bashing my head against my desk trying to figure this out :)

ok i know the MouseDown events work on Run objects (from memory i think also on TableCell's...or at least MouseEnter events work), however my problem is i need "keyboard" focus...and the user is able to navigate they're way around within my rtb purely via keyboard (tabs, arrow keys, etc), in which case i would need supplementary event fires along with MouseDown events to simulate a "normal" GotFocus event...which from my understanding should be handled from a GotKeyboardFocusEvent anyway.

my second problem would be that i need event firing on LostFocus as well, so by using a workaround method i would then need to start keeping track of my current/last 'active' TableCell and keep comparing every time i use my work around event(s).

my third problem is that i need basically the same GotFocus/GotKeyboardFocus handlers to register event firings on my FlowDocument.Blocks objects to execute similar methods.

i fear there has to be a simple'ish solution to this crazyness otherwise building a work around solution is going to be a nightmare..not to mention a major speed hit.

anyways, appreciate the suggestion..hopefully theres something more suitable/efficient out there...
0
 

Author Comment

by:gem56
ID: 35488809
..just as a side note, i've tried registering class handlers for TableCells, Paragraphs and Runs on GotFocus and GotKeyboardFocus events with "handledEventsToo" set to True just in case somethings handled internally...none seem to fire :(
0
 
LVL 96

Accepted Solution

by:
Bob Learned earned 2000 total points
ID: 35495716
How's 'bout using the RichTextBox.SelectionChanged event to query the Paragraph, get the Run, and apply formatting:

Private Sub richTextBox1_SelectionChanged(sender As Object, e As RoutedEventArgs)
	Dim paragraph As Paragraph = richTextBox1.CaretPosition.Paragraph

	Dim run As Run = TryCast(paragraph.Inlines.FirstInline, Run)

	Me.DebugText.Text = run.Text
End Sub

Open in new window


<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*" />
            <RowDefinition Height="10*" />
        </Grid.RowDefinitions>
        <RichTextBox Name="richTextBox1" Grid.Row="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" SelectionChanged="richTextBox1_SelectionChanged" IsDocumentEnabled="True" />
        <TextBox Name="DebugText" Grid.Row="1" HorizontalAlignment="Stretch" Background="#FFD4CCCC" TextWrapping="Wrap" />
    </Grid>
</Window>
0
 

Author Comment

by:gem56
ID: 35500523
Hello TheLearnedOne,

unfortunately that solution isnt viable as my flowdoc can be up to about 30 - 40 pages. so unless theres a way within that routed event to determine whether the selection change was caused by certain keys (arrow keys, home, end, page up, page down) or a mouse click event, then i'd be facing a major speed hit checking the format of my run text and keeping track of my last active tablecell, etc etc.

any other ideas?
cheers
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 35500630
You lost me on that last one...why would you need to know the reason for the selection change?  I think this is a case where I don't have the "bigger picture"...
0
 

Author Comment

by:gem56
ID: 35502962
sorry mate. ok the idea is that we have an rtb with a flowdoc. the content within the flowdoc will basically be a combination of tables (and table data) and normal word text. so basically something similar to what would be a ms word/excel blend.

the problem is two fold. one problem is that whichever tablecell (within any table in the flowdoc) has focus needs its text formatted (methods already exist) based on whichever column it belongs to whenever it gains and loses focus. for example we have various columns, some columns formatted to currency. the idea is that for these 'currency' cells, whenever the user selects/focuses into them, the text reformats from currency to plain numeric...and when they lose focus, the text formats back to currency.

the second problem is that as the flowdoc has essentially two different "input modes" (table and text), we need to keep track of the current mode as both modes have their own behavioural characteristics. only one input mode exists for each flowdoc block. so for example the first 3 blocks of our flowdoc contains normal text, the forth block contains a table. we need to know which block the caret is in so when the user presses the enter key, we know which method to execute.

the idea was that for problem 1 we could write some GotFocus and LostFocus events for our TableCell objects that would handle the formatting, and for problem two we could write another GotFocus event for our Block objects that would basiaclly check the input mode and store it.

the bigger problem here is because our flowdoc will be up to about 30 pages worth, implementing a KeyDown or SelectionChange event would be very time costly as we'd basically have to keep track of which object has focus ourselves and recalculate every time a keys pressed to determine if focus changed, etc etc.
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 35505571
"implementing a KeyDown or SelectionChange event would be very time costly as we'd basically have to keep track of which object has focus ourselves and recalculate every time"

That doesn't make sense, since what I showed you would be all that you would need to keep track of the current paragraph, and from that you should be able to get other information, such as owner TableCell.

Private Sub richTextBox1_SelectionChanged(sender As Object, e As RoutedEventArgs)
	Dim paragraph As Paragraph = richTextBox1.CaretPosition.Paragraph
	Dim run As Run = TryCast(paragraph.Inlines.FirstInline, Run)

        If run Is Nothing Then
             Throw New NullReferenceException("Could not get Run from Paragraph")
        EndIf

        Dim cell As TableCell = TryCast(paragraph.Parent, TableCell)

        If cell Is Nothing Then
             Throw New NullReferenceException("Could not get TableCell from Paragraph")
        EndIf
End Sub

Open in new window

0
 

Author Comment

by:gem56
ID: 35510035
Hello TheLearnedOne,

yes I'm aware that I'll be able to track the current paragraph and therefore TableCell, however i need to simulate a LostFocus event on my TableCells to change the text formatting within the cell's run when the user moves into a different cell. Therefore without a "real" GotFocus and LostFocus event firing, then I'll need to keep track of the "current" TableCell that has focus, then check it every time a KeyDown or SelectionChange event fires, check if the 'last' TableCell is the 'current' TableCell and if not call my own LostFocus method on the last TableCell.

This I assume would be the time consuming part as having to check and compare the last active and current TableCell objects every SelectionChange will get time consuming. Using a KeyDown i expect might be quicker as we could check if the KeyDown 'key' is an arrow key or home/end/etc...although a KeyDown event doesnt cater for changing the caret position with a mouse click.

at this point im guessing that the internal functionality doesnt exist for TableCell objects to trigger GotFocus and LostFocus events, in which case what would be more time consuming processing wise: a KeyDown (checking is key is Home, End, Page Up, Page Down, Arrow) + MouseClick combination, or a SelectionChange ?

cheers
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 35512494
Would it be possible to show me what you are working with?  Focus is pretty tricky in WPF, and I have no idea how to override the default behavior for the TextBoxBase.
0
 

Author Comment

by:gem56
ID: 35548832
hi TheLearnedOne,

i've just sent an email to your experts exchange account. the password for the archive is just your username.

cheers
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 35734519
The question has gone a little past my understanding of WPF, and I haven't had much time to devote to research...
0
 

Author Comment

by:gem56
ID: 35734655
hey look no dramas mate. im guessing theres probably just no nice way of doing it and i'll have to build some sort of work around for it. i'll keep the question open for a few more days in case anyone else can provide a workable solution, otherwise i'll just award it to you for all your help :)

cheers TheLearnedOne
0

Featured Post

Get your Conversational Ransomware Defense e‑book

This e-book gives you an insight into the ransomware threat and reviews the fundamentals of top-notch ransomware preparedness and recovery. To help you protect yourself and your organization. The initial infection may be inevitable, so the best protection is to be fully prepared.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Creating an analog clock UserControl seems fairly straight forward.  It is, after all, essentially just a circle with several lines in it!  Two common approaches for rendering an analog clock typically involve either manually calculating points with…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
With just a little bit of  SQL and VBA, many doors open to cool things like synchronize a list box to display data relevant to other information on a form.  If you have never written code or looked at an SQL statement before, no problem! ...  give i…

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question