Events in an InfoPath 2010 Add-in - c#

I'm currently trying to implement a simple Add-In for InfoPath 2010 Filler/Editor mode, which adds a few buttons on the "Insert" ribbon, which upon clicking inserts some "template" data from another source.
It works fine but the thing that's annoying me is that when the user has no field selected, it remains enabled while all of the other buttons on the insert toolbar somehow "know" that nothing can be inserted in the current context and are therefore disabled.
The MSDN documentation on how to interact with the underlying XDocument is perfectly adequate, but what I'm struggling to figure out is how to interact or get information from the editing UI.
This is what I'd like to have:
An event that gets fired when the user changes from field to field on the form
Then be able to tell what kind of field the user is currently entering data into (i.e. rich text, plain text etc), so the extra buttons can be enabled or disabled as needed.
I thought this would be fairly simple but I've spent nearly a day looking through everything I can find, and have come up empty!
Or have I completely missed the point here?

Several months later I can finally answer my own question. Not that anyone uses InfoPath filler, but just in case anyone does, here's my solution:
There's several points to my original question.
1) Event that gets fired when the user changes from field to field:
This turns out to be specified in the Ribbon Button XML as the "getEnabled" attribute. InfoPath calls the specified function each time it thinks the button may need to be enabled or disabled. On mine I specified: getEnabled="OnButtonGetEnabled", then implemented a small function:
public bool OnButtonGetEnabled(Office.IRibbonControl control)
{
ribbon.Invalidate();
return HaveRichTextFieldSelected(GetContextXPath());
}
in my case 'ribbon' is my instance of Office.IRibbonUI. Calling 'Invalidate()' is pretty important otherwise InfoPath only ends up calling this once.
2) How to determine the type of the field the user has selected.
I'm still not happy with my solution for this but at least I now have something that works.
I've written two functions:
1: GetContextXPath() which calls Globals.ThisAddIn.Application.ActiveWindow.XDocument.View.GetContextNodes(), builds an XPath string from the result (walking backwards through the DOM tree)
2: HaveRichTextFieldSelected() which checks if the specified XPath is of type 'rich' in the manifest (whose DOM tree is under Globals.ThisAddIn.Application.ActiveWindow.XDocument.Solution.DOM)
Anyway I'm not posting all of the code involved here as it's too much for an SO answer, but this should give someone with some common sense a clue as to how to implement this.

Related

How to do automated test with dynamically created controls?

I'm trying to automate a web application, which generates controls in pages dynamically, and the web controls's ID are never the same.
I'm using Visual Studio 2012 Ultimate, MTM and Coded UI Tests. The application is being built with C# and Visual Studio 2012
The problem is that as the control's ID changes with every new run, the tests always fail.
Is there any way to solve this?
If the control id is changing you may use any other identifier to get the controls, like classname, tagname etc.
If classname is also dynamic then you can switch to tagname and get inner HTML of the control in order to confirm that the control is same as expected.
Then you would be able to work with the issue.
I am not very sure about this situation but I can given you an example and probably you can simulate this with the actual situation:
example: Like Loadrunner tool (used for performance testing), when it records the user action, it captures everything including all dynamic values of session id, so now if you replay your script it will fail because at time time of rerun, session ids are changed because of dynamic nature.
How we handle this this: We take the page source and mark the left and right boundary between which dynamic value appears and store the dynamic value in some variable so next time you run, you don't ned to worry about dynamic value.
Not to confuse you, but similarly, you can take the page source, mark the right and left string, store the value between these marker in a variable and handle that. For marking you can use some regular expression ... hope this helps. !!
Lets say you have a button on your web app, and you want to click on that button. In your situation where the ID is dynamic, I would not record the click on the button. You need to create the button dynamically, and add search properties on the fly. See code below.
// Create instance of a html button as a test step.
HtmlInputButton myButton = new HtmlInputButton(someUIMap.UISomeWindow.UISomeDocument);
// Search for the button in the specified UI document as a test step. Here we can search by the DisplayText property.
myButton.SearchProperties.Add("DisplayText", "Your buttons Display Text");
// Click the button if it exists.
if(myButton.Exists)
{
Mouse.Click(myButton);
}
I hope this helps.

SPContext.Current.FormContext.OnSaveHandler Not Firing from Custom Field Type Control

I am having the exact same problem described here. Unfortunately because I don't have 50 points yet I can't comment on it so I have to create a new duplicate question.
I mean it's not "100% EXACTLY" like the other guy's problem because for me the problem exists on the Edit Form and I'm using a combination of custom forms and fields. But I am adding the custom save event handler at the field level per suggestion #2 made by the guy at this site. I should also note that when I create a new Document Library without any custom forms or Content Types and just use my custom fields straight-up, the event handler also does not fire. If however I create a new regular SharePoint list and add the custom fields then the OnSaveHandler DOES fire! I So I'm not quite sure why it doesn't work in Document Libraries but it does work in lists because I was under the impression that the beauty of custom fields was that they operate independently of everything else. Meaning, even if I was doing something wonky with my Edit Form or some other control, since I am attaching my custom method to the SPContext.Current.FormContext.OnSaveHandler in the OnInit method of my custom field then that should fire no matter what! Even when the field is being loaded for the first time I actually see the event being wired up in the debugger. In debug mode I have a breakpoint next to the "if" statement below and it hits that breakpoint which means that when the FormContext.OnSaveHandler is triggered my method should fire.
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if ((SPContext.Current.FormContext.FormMode == SPControlMode.New) || (SPContext.Current.FormContext.FormMode == SPControlMode.Edit))
SPContext.Current.FormContext.OnSaveHandler += new EventHandler(MyHandler);
}
Any thoughts? Suggestions?
Thanks!
UPDATE #1: After a little troubleshooting I was able to deduce that the EventHandler in my custom field was being fired but ONLY when used in regular lists and NOT Document Libraries! In regular SharePoint lists not only is the SPContext.Current.FormContext.OnSaveHandler being fired but the values from the custom fields are being saved as well.
As a side note, when saving the data back to my custom field that inherits from SPFieldText, the value (which is json data) displays in the list view as #VALUE!, which I think is kind of weird. I mean it's able to read the json data that's stored in the field correctly because it shows up in the Edit Form just fine. But for some reason SharePoint just displays it as #VALUE! in the list view.
So after many frustrating hours it looks like there are several issues that arise when using custom fields in a Document Library.
You can't use them in any meaningful way and expect the data to be saved when using a custom upload page. In other words, if you want to create your own custom upload page that combines the file upload input field and browse button along with your own custom fields embedded in a ListFieldIterator then the values WILL NOT BE SAVED. This is a fact! The reason is that the operation for uploading the file and creating the initial ListItem along with generating it's ID value occurs ASYNCHRONOUSLY with respect to the ListItem EventReceiver. So what does this mean exactly? It means that when you try to access the values stored in your custom field(s) in the SPItemEventProperties parameter of the ItemAdded method in the ListItem's Event Receiver all of those values will be null since the current SPContext is completely unaware of the existence of those fields and their respective values because all of the events that occur with respect to the initial document upload are executed in a different thread...asynchronously. Conversely, when the custom fields attempt to "save themselves" back to the newly uploaded document the SPField.ListItem's document ID is still set to zero because these custom fields are...you guessed it, executing in a different thread and are not "in synch" with the upload event that took place which generated the new document ID. Although I've read about a few different workarounds regarding this issue, none of them seem to work, or they are very convoluted or require you to abandon using custom fields which isn't really a workaround but more of a "throwing in the towel". One suggestion was to simply update the Elements.xml file for the EventReceiver by simply adding a "Synchronous" entry to force the event to occur synchronously instead of asynchronously. At first I thought this was too easy and too good to be true. As it turns out, I was right. :)
You can't nest a custom ListFieldIterator inside a custom control and expect your custom fields to save the data that they contain. You MUST use the ListFieldIterator directly in your form template. Period! If you try and wrap the ListFieldIterator with your custom fields in a custom control you will be very frustrated with the results.
As a side note, once the document has been uploaded and an ID has been created, you CAN enter data into your custom fields in the Edit Form and the values WILL be saved because now your code will actually be able to reference the ListItem's ID value since the ListItem will already exist in the list. Again, this is contrary to a custom upload form where the ID for the ListItem does not yet exist because you haven't actually uploaded the document yet.
I REALLY wish that Microsoft would provide some sort of update that would allow developers to get around this issue with Document Libraries and I think that it's pretty clear that they knew this was an issue when they first released SharePoint which is why the default behavior for the Document Library "New Form" is to present the user with a standalone Upload form which then redirects the user to the Edit Form so that they could avoid all of this. Of course this leaves developers who wish to allow users to upload a document and enter data on the same screen without a leg to stand on when using custom fields. Your only alternative is to use custom forms and programmatically set all of the field values and add in tons and tons of conditional logic for every single permutation of all the different fields and layout possibilities but that's a whole other animal and certainly defeats the whole reason why Microsoft created the concept of custom fields in the first place!

Telerik mvc combobox: Prevent write value different from the list

I have a telerik combobox in mvc3 application and I want to prevent the user writing a value different from the list being loaded from the controller.
A thing that partial helped is to set the textbox input to be readonly but then:
1. The user can filter the list by the textbox.
2. The user can erase his selection.
Another thing that I thought about is: What the user types in the select is the value not the description, so I need it to prevent writing text different from the description while the value remains encapsulated.
Are you still looking to have the user be able to input custom text? If not you can use the DropDownList functionality as seen on this demo page.
If you still want the user to be able to type into the component but somehow have it aware of when they either misspell something, or type one character more than necessary, this can be extremely difficult. You would essentially have to have some clever JavaScript to be triggered with every key press and check the current value against a list. With users being pretty quick with typing, or their browsers being old, this can be very unreliable. Plus, a user can easily disable JavaScript at any time making this functionality obsolete.
I think your best options is to have it as is, where the user can type whatever they want. You can always have validation on the item they have typed and upon blur() or a POST (whatever fits your application) have a message appear to warn them of an invalid entry.

dynamic window focus MVC2

I am working on an MVC2 project, on a view we display a large data set which refreshes every minute with latest data..some specific records are updated every minute in this data set. I want the browser to focus on these specific records..Not sure how to use javascript focus() here dynamically...
any clue?
thanks,
You need to provide more detail as to exactly what you are attempting to do.
If you are attempting to focus just ensure each record has a unique identifier then you can focus on individual records.
Alternatively you could simply keep the focus at the top or bottom of wherever you are displaying them.
EDIT:
In that case I would suggest something like the following
var currEle = document.getElementById("Record123");
currEle.focus();
Suppose you know how to issue an Ajax call and return either partial view or JSON data and how to use that data on the client afterwards...
You can only focus to a point in the document when
there's only one change or
all changes are summarised together in the same document area
We're also not talking about focusing as in document perspective, but rather about focusing of users attention to document specific content (or part of it).
First option
You can always use something like jQuery.scrollintoview() plugin (link to blog post that describes the plugin here) that will scroll document to the record that changed and highlight it using jQuery UI effect highlight. Linked blog post also describes the purpose of visual animated scrolling instead of simple jumping within the document.
Second option
Put changes at the top and keep your document scrolled at the top when content gets updated. You can blink a few times some icon informing the user of the changed content in the changes area.

Argument exception occurring on form.ShowDialog() when I change the sortorder of the form's data grid

Ok, I'm utterly confused by this situation, so bear with me.
In my application, if you click on a button I have an editor form open
dgEditor = new fmDataGridFieldEditor();
dgEditor.ShowDialog();
This works fine, and my form shows up and operates correctly. The form has a data grid in it with some specified fields. Now, if I then change data in one of the columns of the datagrid (a column that is just meant for numbers) and then change the sorting order by clicking on the column header, my form crashes. with an ArgumentException error that says "Object must be of type Int32" on the dgEditor.ShowDialog(); line.
I don't understand what is going on or even how to start debugging this. This doesn't happen when I modify existing rows, or if the rows I enter are already sorted (e.g. 0,1,2 is fine but 0,1, 0 causes the crash).
Furthermore, I have visual studio 2010 setup to break on all exceptions, not just unhandled ones, but I'm getting an exception in the same place.
Finally, I tied the data grid's ColumnSortModeChanged event to show a message box, but even when the sorts don't crash the form, the message box doesn't show.
I'm at a loss on how to proceed with this.
The debugger shows the last line of code that you wrote. Which is the ShowDialog() call. If you look at Debug + Windows + Call stack then you see the methods in the .NET framework that are involved. Scroll the window up if necessary to see them all. DataGridView has a lot of built-in functionality, the source code isn't readily available although you can get it from the Reference Source. Not that this will help much, there's rather a lot of it.
Clearly there's some invalid data in one or more rows. Looks like a leading space, only guessing here without sitting in front of your machine. Implement the CellValidating event so the user cannot enter an improperly formatted number.
I just had this happen to me in VB. What I discovered was that when I copied the values from a textbox into the grid I didn't do a cast to int. Being VB I assumed it would cast implicitly, but the cell value is, I guess, an object, so it happily took a string. Everything looked right and worked right, until I happened to sort on that column. Maybe this will help someone else.
ShowDialog will throw an error if you are trying to create a PictureBox dynamically on the TableLayoutPanel. It does not allow two PictureBox elements to add a similar index on the Table or you could have a error if your are using MemorySTream and not closing it properly.

Categories