Updating contents of an iRibbon control from another control's callback - vba

Back in the old days of VBA, we used to be able to directly access controls on a form by name. I'm a little perplexed by how to do this in VBA 2010 (or if it's even possible any longer).
Say I have a ribbon control with a dropdown list called "channelList", and elsewhere on the ribbon I have a textbox called "labelText". Each of these items has a unique callback function - when I type something into labelText, its callback fires, and when I select an item from the channelList listbox, its callback fires with the list item passed as an argument.
Where I'm stumped by is how I would update the labelText textbox contents with 'something' from within the channelList callback.
Is there a way to directly access the textbox control from within the listbox callback, or must I generate some sort of event? What method or function would I use to set the text value for the control? (Do I need to cast the IRibbonControl object to something?)

The solution was a combination of an answer and the comments, so here goes:
Add a "getText" callback subroutine name to the Ribbon XML, specific to the "labelText" editbox.
editBox id="labelText" label="Text:" sizeString="xxxxxxxxxx"
onChange="TextboxCallback" getText="UpdateTextBoxText"
screentip="Channel label"
supertip="Limited to 10 characters. Press Enter once finished typing."
In the combo box callback function, set the desired editbox text to a global and call Ribbon.InvalidateControl with "labelText" as the argument.
MyRibbon.InvalidateControl "labelText"
Implement the editbox callback, passing a handle to the ribbon and another variable ByRef to contain the 'stuff' to be updated. Use the global to update the control's text via the ByRef argument.
Sub UpdateTextBoxText(control As IRibbonControl, ByRef returnedVal)
Select Case (control.id)
Case "labelText"
returnedVal = LabelText
End Select
End Sub
I guess this is "progress". labelText.Value = "blah" is far too simple.

Take a look at the Ribbon.Invalidate method. When you "invalidate" the ribbon you basically reset it, and in that moment you can set the properties of controls on the ribbon based on whatever you can track in that moment. In order to do so, you need to have Control.GetEnabled, GetVisible, etc., subroutines in your VBA.
You can also invalidate individual controls with Ribbon.InvalidateControl.
Here's a link that might help: http://sourcedaddy.com/ms-excel/resetting-controls.html

Related

Listbox not displaying in UserForm

I'm trying to display a listbox in a UserForm from a separate sheet called "Fields". The problem is, the list will not display. It shows as a drop down arrow next to the cell, but not in the userform like I'm wanting.
Private Sub UserForm_Activate2()
On Error Resume Next
Me.ListBox2.Clear
For Each element In gFieldsListArr
Me.ListBox2.AddItem element
Next element
UserForm_initialize2
End Sub
Private Sub UserForm_initialize2()
For Each element In Split(gCellCurrVal2, ",")
For ii = 0 To ListBox2.ListCount - 1
If element = Me.ListBox2.List(ii) Then
Me.ListBox2.Selected(ii) = True
End If
Next ii
Next element
End Sub
TL;DR: You can't rename event handlers or change their member signature in any way*, because the correct member definition is defined by the event, not its handlers.
Watch the dropdowns at the top of the editor as you navigate between procedure scopes:
Whenever the left-side dropdown says (General), you're not inside an event handler.
Contrast with:
The left-side dropdown is listing all available interfaces and event sources; to handle the events of a form, you must pick UserForm from that dropdown, and then pick a member from the right-side dropdown.
When you do this, the VBE creates the procedure stubs for you, with the correct name and signature every time.
Whenever you navigate to what's intended to be an event handler and the left-side dropdown says (General), you're looking at dead code that isn't responding to any events.
* You may change the accessibility from Private to Public, but invoking an event handler directly is a design smell so there shouldn't be a need to do that. You may change the parameter names, but not their type; renaming handler parameters is a rather surprising thing to do though, and best avoided too. So yeah, best not change these member signatures in any way.

Word - how to uncheck checkboxes?

I have 4 checkboxes but we need to restrict selection to just a single one, meaning if you check the first, the other 3 will go unchecked. I know we could use ActiveX radio buttons but we'd prefer to avoid ActiveX if possible, plus with check boxes we have more control over the layout.
I've set the name of the checkbox appropriately to Check1:
And then I've put this very basic script into the Visual Basic section:
Private Sub Check1_Click()
Check1.Enabled = True
Check2.Enabled = False
Check3.Enabled = False
Check4.Enabled = False
End Sub
But unfortunately checking the first box doesn't uncheck the next 3.
Any ideas please? Thank you!
If these are Content Controls, as you indicate, then they do not have a CLICK event. Nor can they be identified by VBA by their Title property. The code you show us is for ActiveX controls, which you say you don't want to use...
Working with content control events is not as simple and intuitive as with ActiveX controls. Similar to form fields, Content Controls only have "editing" events that trigger on the user entering and exiting the content control. These events are available in the ThisDocument module, in the Document category.
The same ContentControlOnExit event triggers for ALL content controls in the document, so you need a Select Case or If conditional to query the ContentControl argument in order to know which content control was exited.
In order to address the other checkboxes you need to use the Document.SelectContentControlsByTitle (or ...ByTag) method which returns an array of all content controls with that title (or tag).
If you really want to emulate a "click" event then you need to insert a Custom XML Part in the document with nodes linked to the content controls. When the user changes the state of the control the ContentControlBeforeStoreUpdate event will trigger, letting you take action.
The property you need is Value, not Enabled.
The purpose of property Enabled is to prevent a control from being changed by user.
Additionaly, you need to prevent it from the events cascade. It means that when you change programatically the value of Check2, this will trigger Private Sub Check2_Click() and so on.
In order to make it work you should change your code like that:
Private Sub Check1_Click()
If Check1.Value Then
Check1.Value = True
Check2.Value = False
Check3.Value = False
Check4.Value = False
End If
End Sub
and similarly for the other check boxes.
For your purpose radio buttons will be better choice. Radio buttons have built-in functionality to uncheck currently selected button if other one is checked.

Word 2010 VBA Checkboxes

Hopefully an easy one.
I've got a Word document littered with Checkboxes. Is there any way to access these checkboxes as a collection I can loop through and check/set properties such as ID and Value?
For reference, I've already tried the ActiveDocument.ContentControls collection; it's empty.
I've also tried ActiveDocument.Fields. This actually contains the same number of checkboxes as there are on the page, but I can't cast it to a Checkbox to access the properties I need.
One final question, is it possible to dynamically assign an event handler to the click?
Thank you in advance
The collection of all ActiveX fields embedded in your document (let's say its name is ThisDocument) is the collection ThisDocument.Fields. The items of this collection are objects of class Field.
To query the value of the objects in this collection, you'd use something along the lines of:
ThisDocument.Fields.Item(1).OLEFormat.Object.Value
To add code to the event handlers, just right-click on the ActiveX control, and then select "View Code" from the context menu. You'll get the Click event handler:
Private Sub CheckBox1_Click()
' empty if event handler not set, VBA code otherwise '
End Sub
To insert code dynamically, you need to manipulate the Code Module directly, and add the event handlers line by line. This might be tricky but, basically, you'd do something like:
ThisDocument _
.VBProject _
.VBComponents(ThisDocument.CodeName) _
.CodeModule _
.InsertLines(<<Line>>, <<String>>)
where <<Line>> is where you want to insert (number), and <<String>> is the text that you want to insert. Be careful not to insert in the middle of an existing Sub, Function or custom type definition (obviously).

pass control values window forms

I have a form with 5 controls.
For textbox I am accesing like frmNote.txtNumber.Text.
When I am accessing this property directly from form frmNote then I am getting the value of textbox.
But when I created a method for example NewMethod() in different vb file and call this method from frmNote form button click event then I am not able to access frmNote.txtNumber.Text value over there inside method.
It is coming blank. Do I need to pass all control values to method from form or is there any other way around.
Because txtNumber isn't shared, you can't access it from other class. You must pass it's value to NewMethod. Code will look like this:
Public Sub NewMethod(text as String)
'Use text
End Sub
And calling NewMethod:
NewMethod(txtNumber.Text)

Built in Arguments in Custom Event

When I want to add an event to a form built in Microsoft Access 2000, I use the [Event Procedure] option. Some of my events are global functions I created in VBA so that I can just enter the function name in the event property. For instance, I have a back button on my forms that have this as their OnClick event property: =GoBack().
I want to be able to use the built-in arguments in my custom functions as the event property. For instance, the Form_Error event has two arguments: DataErr and Response. In my global =HandleFormError(), I want to be able to set the Response variable.
Is this possible, and if so, how would I be able to accomplish this?
I'd say your best bet is to do something like this
Private Sub Form_Error(DataErr As Integer, Response As Integer)
HandleFormError DataErr, Response
End Sub
and do all your logic in HandleFormError. There is no way to link Form_Error to any method other than Sub Form_Error(DataErr As Integer, Response As Integer). This is just a VBA restriction.
For events like Click you can put your functions in the expression builder (makes for easier copy/pasting) but are probably just as well off doing this in a regular Form_click style event.