Sequence of keyboard focus events and tag setting

Hi all.

I have been investigating processing of TextBox contents based on detection of keyboard focus events.

I had assumed that if an entry is typed and then the TAB key hit … detection of keyboard focus leaving the TextBox would guarantee that the associated tag value had already been set.

My investigation suggests that this is not the case … which seems very odd to me.

If an entry is typed and the ENTER key hit, followed by the TAB key … the tag value is seen, as this is ensured through earlier use of the ENTER key.

Surely it would be sensible if use of the TAB key to leave the field had the same effect. Anway … assuming there is a good reason for ignoring the data entry, does anyone know of a work-around method to implement that behaviour?

I am aware of the ability to introduce KeyDown and PreviewKeyDown handlers. Could they be used to ensure the entry is written to the TextBox tag?

Regards,
Greg Shearer

Hello Greg,

We understand you are having and issue while trying to save a Tag value by changing TextBoxes pressing TAB.
On our tests the Tag value is saved automatically when the TAB key is pressed.

To assist you further, could you kindly provide us with additional details about the configuration of the textboxes in your project? Additionally, it would be helpful for us to know which version of FactoryStudio you are currently using.

Best Regards,
Tatsoft Team.

Hi.

Just to be clear … the Tag value is saved when the TAB key is hit … however it appears to be saved AFTER IsKeyboardFocusWithinChanged indicates that focus has left the TextBox.

I had expected the Tag value to be saved BEFORE IsKeyboardFocusWithinChanged indicates focus change, so that the value could processed according to the application requirements. That is, I would like to test/process the Tag value ON EXIT from the TextBox. Is there a standard method available for this need? If so, I have not found it.

Is my interpretation above correct? I believe that it is, but it does also seem odd to me that IsKeyboardFocusWithinChanged should indicate before the Tag value is set.

My license details are:
image

Hello Greg,

By default, the Tag Value is saved on the “LostFocus” event. However, if your project requires using the “IsKeyboardFocusWithinChanged” event, you can follow this simple workaround: Assign the Event handler and retrieve the name of the Tag assigned to the TextBox:

Assign the Event handler and retrieve the name of the Tag assigned to the TextBox:

TTextBox textBox1;
textBox1 = this.CurrentDisplay.GetControl("textBox1") as TTextBox;
textBox1.IsKeyboardFocusWithinChanged += this.TextBox_IsKeyboardFocusWithinChanged;
textBox1.Tag = @Tag.Text1.GetName();

In the Event handler, make sure to declare the sender as TTextBox and use TK.SetObjectValue to update your Tag value:

private void TextBox_IsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
{
	TTextBox textBox = sender as TTextBox;
	if(textBox == null)
		return;
		
	string tag = TConvert.ToString(textBox.Tag);
	string text = textBox.Text;
	TK.SetObjectValue(tag, text); 
}

Following this method, the updated tag value can be utilized within the event handler.

Please let us know if you have any other questions.

Best Regards,
Tatsoft Team.

Thanks for your response, as I expect that method will help with my problem.

However I should ask … can the LostFocus event be used in a similar way but more directly?
I think I had investigated that earlier, but hadn’t had any succes.
If you can similarly indicate how LostFocus could be used, I will try that as well.

I apologise for asking what may seem very basic questions, but from my perspective these methods seem to assume some underlying expert knowledge … which I clearly don’t have.

I do appreciate your assistance :slight_smile:

Regards,
Greg Shearer

1 Like

Hello Greg,

We´re glad the method provided seems helpful for your problem.

The LostFocus event can be used similarly the IsKeyboardFocusWithinChanged, like below:

textBox1.LostFocus += this.TextBox_LostFocus;

In the Event handler:

private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
    // Your code here.
}

A more directly way to create this is shown below:

textBox1.LostFocus += (sender, e) =>
{
    // Your code here.
};

Please let us know if you have any other questions.

Best Regards,
Tatsoft Team.

Hi again.

I have been trying out use of the LostFocus event, and thought all was going well … but have found another confusing issue.

When I use the Handler routine below with the MsgBox included, all works well:

confirmation = CurrentDisplay.GetControl(TTB_confirmation)
confirmation.Tag = @Tag.sample.confirmation.GetName()
AddHandler confirmation.LostFocus, AddressOf ConfirmationFocusLost

Sub ConfirmationFocusLost()

MsgBox(@Tag.sample.confirmation)
@Script.Class.sample_identification.confirmation_changed()

@Tag.processing_grid= 0
End Sub

I do realise that placing a MsgBox() within a handler is not recommended … but it seems to indicate that the tag has been set. I now suspect that is an illusion.

image

That is, @Tag.sample.confirmation appears to be available within the Handler, and when the MsgBox is closed the following procedure behaves as expected.

However … when the MsgBox is instead placed within the executed procedure … the tag appears to not have been set.

image

So … I remain confused … as it appears that the tag value has not actually been set by the time the LostFocus event is raised.

Hello Greg,

We made some tests and when the MsgBox is placed within the executed procedure, the tag had been set too.

Can you send us a example tproj file that implements exactly what you are saying? So we can run some tests to determine what is causing your problem.

Bests Regards,
Tatsoft Team.

I will put together a small application when I have the chance … but that may be a while off … and it probably won’t display the same behaviour knowing my luck.

However, within my current application there definitely seems to be a system timing related problem.

If I place MsgBox within the called procedure it consistently displays the tag as being empty, even though TraceWindow and Property Watch indicate that the tag is set.

More particularly, if I place MsgBox before the tag is first referenced, by the time I click the ok button the tag is seen as set, so the procedure executes as if the tag is set.

image

However, if I place MsgBox after the tag is first referenced, the tag has already been acted on as if it is not set.

image

Any ideas?

PS
The time interval reported in TraceWindow between the tag (Tag.sample.confirmation) being set and it not being seen within the called procedure is 2 ms, as shown below.

Also … this behaviour is the same even when the procedure is run from the GotFocus event of the field being tabbed into! This is the configuration in place for the above image. The behaviour is as if there are two slightly different views of the tag within the application … which I’m sure can’t be the case.

Hello Greg,

It appears that you have some problems with the MsgBox within the executed procedure, is it really necessary to use the MsgBox or executed a procedure to check the tag value?

If not, to ensure that the tag value is indeed properly set, you can incorporate the following script into the LostFocus event. This script will enable you to trace and verify the tag value:

private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
	TTextBox textBox = sender as TTextBox;
	if(textBox == null)
		return;
		
	string tag = TConvert.ToString(textBox.Tag);
	string tagValue = TConvert.ToString(TK.GetObjectValue(tag));
	
	@Info.Trace("TextBox_LostFocus || Tag: " + tag + " || TagValue: " + tagValue + " || Text: " + textBox.Text);
}

If it doesn’t helps you, we await the example tproj file to make some tests.

Please let us know if you have any other questions.

Bests Regards,
Tatsoft Team.

Hi … it has been a while.

I haven’t prepared a test application … but I do have a clearer demonstration of my problem using just Trace output … no MsgBox() involved :slight_smile:

Just to be clear … I don’t need to use MsgBox() for any purpose … I was just using it as a display tool.

However, the same problem is shown from Trace output.

In the detail below I have configured a handler for loss of focus on a field for Tag.confirmation.
image

When I enter a string into the field and TAB out, the handler executes and the tag value is shown as set within the Trace window. Also, the script get_job_details() executes as expected.

image

However, when the same tag (Tag.confirmation) is output from within the script get_job_details() … it is shown as blank … How can this be!!!

image

As a result, the script acts on an empty string and does not return the expected data.
If I click in the Tag.confirmation field to return focus, then TAB out again … the script now sees the tag correctly. So … there is an apparent lag between the tag value being seen within the screen versus within the script.

This clearly illustrates the problem I am having.
That is, a tag which is indicated as being set on loss of object focus within a screen … IS NOT SEEN AS SET within a called script. This seems to make it impossible for me to reliably use loss of focus and similar characteristics to build my tab/enter/arrow key driven operator interface.

But more to the point … how can this happen??? Am I missing something obvious … or is it possible for individual tag values to appear as asynchronous within an application???

If you have suggestions for better approaches to use for my application, any ideas will be appreciated.

PS on this issue …

I can overcome this specific issue by passing the tag value as a parameter to the script. However … this does nothing to explain why the tag value itself is not available within the script. The trace detail below shows:

  1. Tag value seen within the display
  2. Tag value seen within the called script
  3. Value passed to the script

Hopefully you can understand why this has me concerned, as I have experienced similar issues regarding the apparent synchronicity of tag updates when moving through data grids using TAB/ARROW keys.

Hi.

I’ve attempted to produce a stripped version of my application to demonstrate the tag latency issue. However it does not provide the trace statements.

All the application now does is execute the script get_job_details(@Tag.confirmation) when tabbing out of the confirmation field. The get_job_details() only contains trace statements … but the output from the trace statements does not appear.

Can you explain why, and in doing so possibly resolve the problems I am having.

But first … can you tell me how to attach a project file?

Regards,
Greg Shearer

PS
I’ve emailed .rar to noreply@forum.tatsoft.com and included a link below.

Hi Greg,

We received your messages and understood your issues.

We are still analyzing the best option to be taken for this case. We will return soon with a solution for you.

Bests,
Tatsoft Team.

Thanks for looking at this.
Any advice on alternative methods/approaches will be appreciated.
As mentioned in earlier posts … I am not a VB/C# .NET expert.

Hi Greg,

The slight delay you’re experiencing when using server-type classes is a result of the time required for updated client (display) values to synchronize with the server process. On the other hand, when using client-type classes, this synchronization delay does not occur.

To mitigate this, we recommend changing the class’s domain from Server to Client. This adjustment will ensure that the class operates within the client domain, effectively eliminating any delay associated with server synchronization.

Hope it helps you.

Bests,
Tatsoft Team.

Hi Felipe.

Thanks for investigating and confirming the cause … but unfortunately I will not be able resolve my issues using that method … as it has been highlighted to me earlier that the EdgeHMI product only provides Server domain for Tasks and Classes. That is, domain selection is not available.

Unfortunately this could mean a dead-end for development of this particular application within EdgeHMI, which is very disappointing as it is otherwise a wonderful environment and totally adequate for our general HMI needs.

I may investigate upgrading to FactoryStudio level licensing, although this may be an issue, as it could potentially double our future licensing costs for around 100 HMI installations requiring updates over coming years. Of course, that would depend on whether this issue also impacts on our other applications, which it may not … the uncertainty of which, at ths stage, is clearly also an issue.

I will of course continue with some limited investigation of other interface designs, although I am not hopeful of success, as I have already spent far too long on this aspect of the application and tried many different approaches. Unfortunately, the nature of the operating environment in which this HMI application is used, makes regular use of a mouse or touchscreen unsuitable for efficient operation.

Thanks again for your efforts.
It may be worthwhile highlighting the Domain limitations of the EdgeHMI environment somehow within the development environment to avoid others experiencing similar confusing situations in the future.

Regards,
Greg Shearer

Hi again.

I am familiar with the concept of Server and Local tags from another environment, and with the restrictions around functionality available within Server versus Client environments. However I must admit to being puzzled by the application of these concepts to my application … which I have always considered as a stand-alone Server application. That is, I had assumed that as all tags were defined with the default Server scope, there was effectively at all times a single consistent view of application tags.

This is what has confused me about the behaviours I observed … which clearly do not fit this view … and which seems to me to be a significant shortcoming withing the EdgeHMI environemnt.

The application will only ever operate stand-alone, and has no need for additional client interfaces. Anyway, clearly my grasp of the EdgeHMI environment is not yet that strong.

Given that the issue you outlined relates to coordination between Server and Client tags … is it possible to address this by declaring all application tags with Client Domain? I assume not … but thought I would ask the question anyway :slight_smile: At the moment all tags have default Server domain.

Hi once more with a question relating to your earlier response.

Assuming I upgrade our licenses, can you give some insight into how I will know to set class domain to Client versus Server when developing?

As mentioned earlier, I had assumed that the application I was developing was entirely a stand-alone, self contained Server domain application, so it would not have occured to me to configure classes within the Client domain.

So … what are the criteria for determining the correct domain for tasks and classes? Hopefully they are clear …