DocumentBeforePrint does not fire for Envelope print for VBA in Word - vba

I am trying to switch users to use a different printer for envelopes in Word. If they create the envelope, then print it, it works great using DocumentBeforePrint. However, this event is NOT fired when using the Print button on the dialog Mailings --> Envelopes. Is there any event fired when this happens that I can catch?
thanks,
Mike

There is no event, as such, however...
It is possible to Display, Execute or Show Word's built-in dialog boxes. A number of the controls in these dialog boxes are exposed so that they can be set or read. And the button used to dismiss the dialog box returns a value that can be evaluated.
The list of exposed controls is documented here. The WdWordDialog enumerator for envelopes is wdDialogToolsCreateEnvelope. The properties listed are for both envelopes and labels, keep that in mind when sorting through the possibilities. Note that there is no IntelliSense for these properties. (For .NET people reading this, the properties are accessed via late-binding, meaning C# must use PInvoke in order to work with them.)
To read the user's input, place the properties after the method; to make "default setting", place the properties before the method.
Dismissing this dialog box returns the following values:
0 Cancel (or the "X" button)
1 Print
2 Add to Document:
Since you need to do something before the print job is sent, you probably need to use Display rather than Show. Display does not execute the dialog box when the user dismisses it. Instead, it's necessary to capture the settings, do something with them, then Execute the the dialog box.
For example, the following code displays the dialog box to the user, capture's the delivery address typed into that box, then handles the various return values.
Sub PrintEnvelopes()
Dim dlg As Word.Dialog
Dim retVal As Long
Dim recipAddress As String
Set dlg = Application.Dialogs(wdDialogToolsCreateEnvelope)
With dlg
retVal = .Display
recipAddress = .envaddress
End With
Select Case retVal
Case 1 'Print
With dlg
'Change the printer here
.envaddress = recipAddress
.Execute
End With
Case 0 'Cancel
Case 2 'Add to document
With dlg
.envaddress = recipAddress
.Execute
End With
End Select
End Sub

Turns out, there are events you can place in a module to intercept the Envelope tool launch (h/t http://www.gmayor.com/fax_from_word.htm). As such, I added the following to one of my modules, and it runs when Mailings-->Envelopes is selected, so I can switch the printer, load the dialog, then switch the printer back after the dialog is finished:
Sub ToolsCreateEnvelope()
Dim DoChangePrinter As Boolean
Dim OriginalPrinterName As String
DoChangePrinter = False
OriginalPrinterName = Application.ActivePrinter
CurrentPrinterName = OriginalPrinterName
//Change to use color if on B&W printer
If InStr(1, LCase(CurrentPrinterName), "b&w") Then
CurrentPrinterName = Replace(CurrentPrinterName, "B&W", "COLOR")
DoChangePrinter = True
End If
If (DoChangePrinter) Then ChangePrinter
Application.ActiveDocument.Envelope.DefaultOmitReturnAddress = True
//Show dialog
Dim oDlg As Dialog
Set oDlg = Dialogs(wdDialogToolsCreateEnvelope)
With oDlg 'Pop up the envelopes dialog
.extractaddress = True
.Show
End With
ActivePrinter = OriginalPrinterName 'Restore the original printer
End Sub

Related

Show/Hide FileExplorer in Access Form

I've been trying to use a combobox to show/hide a PDF viewer that I've added into a MS Access form.
When I use the form_current event, then the form only updates when I move between the data entries. When I use the afterupdate event, the same code does nothing at all.
Does anyone have a fix? The code I have used is below, which I have tried both the AfterUpdate event for the Browser and the Form_Current event for the whole form
Private Sub PDFT900_AfterUpdate() / Private Sub Form_Current()
Dim ESNComb As String
ESNComb = Me.ESNCombo.Column(1)
If ESNComb Like "9????" Then
Me.PDFT900.Visible = True
Else
Me.PDFT900.Visible = False
End If
End Sub
In the code below, I'm hiding and showing the Adobe PDF Reader ActiveX control named, "AcroPDF0". Since the Like operator returns true on an expression match and false on a mismatch or no match, it serves as a simple boolean switch for the visible property. I've used the (*) wild card instead of (?). It works {shrug}. See demonstration images below.
Private Sub ESNCombo_AfterUpdate()
'AcroPDF0.Visible = ESNCombo.Text Like "P*"
AcroPDF0.Visible = ESNCombo.Column(0) Like "P*"
AcroPDF0.src = acroPDFOSrc
End Sub
ComboBox List Items
"File Browser" Selected in ComboBox
Toggled ComboBox back to "PDFT900"

How do I change the _Click() event on a MS Access Form?

I am hoping to be able to streamline my UI. I want to have a set of command buttons change the _On_Click() event based on a user selection. For example:
Main topic selections: cmd1:"Membership Reports", cmd2: "Administration Reports", cmd3: "Other Reports - TBD"
If the user selects cmd1 then the subtopic buttons properties change to allow the user to open reports in that category.
Sub Topic Selections: cmd4: "All Members", cmd5: "Active Members", etc.
If the user selects cmd2: then the on_Click event would change to open reports in the "Administration Reports" group.
Thanks in advance for your help.
I would use 3 main Toggle Buttons and put hem into an Option group frame (Let's call it FrameMain). Set the Option Value for the buttons as 1,2,3. Create as many regular buttons a you have sub topics (let's call them cmd1_1, cmd1_2, cmd2_1....) and set theirs property Visible to False and Tag to Sub. Now create event FrameMain_AfterUpdate:
Private Sub FrameMain_AfterUpdate()
Dim ctl As Control
For Each ctl In Me.Controls
If ctl.Tag = "Sub" Then
ctl.Visible = False
End If
Next
Select Case Me.FrameMain
Case 1
cmd1_1.Visible = True
cmd1_2.Visible = True
Case 2
cmd2_1.Visible = True
cmd2_2.Visible = True
Case 3
cmd3_1.Visible = True
cmd3_2.Visible = True
End Select
End Sub
You can create now On_Click() event for all your sub-buttons to open the report you want.
You can also use a Switch board (search the Internet how to create it).

Word CheckBox ContentContol OnChange Event

I try to make a word document with two checkboxes where each checkbox will show/hide a part of the document with a custom style.
I plan to set value Style.Font.Hidden = True/False depending from checkbox values, but...
I found that there are 3 types of controls:
Legacy Controls - This seems old the ugly.
ActiveX Controls - I can easyly attach to checkbox onChange events, but these are also ugly and I think it's not that secure, also this is probably now working on mac.
ContentControls - This seems like the right way to do this, but I just can't attach to the right event. (Also there is some XML attachment described, but I'm not using this, this seem too complicated, I don't know.)
Can you tell me how to atach to onChange event of CheckBox ContentContol? I need the same behaviour like it's ActiveX CheckBox.
Content Controls do not have "onChange" events, so you can't get a content control to behave like the ActiveX checkbox in a simple manner. Similarly to form fields, the code for ContentControls fires when the control is entered/exited.
The only way to emulate "onChange" for a Content Control is to link the content control to a node in a CustomXMLPart in the document then work with the Document_ContentControlBeforeStoreUpdate event that triggers when the content of the node in the CustomXMLPart is going to be changed.
If, as your question indicates, this is too complex for your purposes you could use a MacroButton field that displays a font character (Symbol) that looks like a checkbox. Clicking the field would exchange that character for a different one, that looks checked. And the reverse again for the next click. Here's some sample code to get you started. If you don't like the checkboxes I chose, you can pick something else from Insert/Symbols/Symbol. Just change the character numbers and the font name.
By default a MacroButton field triggers on double click. You can change this to a single click when the document is opened in an AutoOpen macro.
Sub AutoOpen()
Application.Options.ButtonFieldClicks = 1
End Sub
Sub ToggleCheckBox()
Dim iNotChecked As Integer, iChecked As Integer
Dim rngCheck As word.Range
Dim sBkmName As String, sFontName as String
iNotChecked = 111
iChecked = 253
sBkmName = "bkmCheck"
sFontName = "Wingdings"
Set rngCheck = ActiveDocument.Bookmarks(sBkmName).Range
If Asc(rngCheck.Text) = iNotChecked Then
rngCheck.Text = Chr(iChecked)
ActiveDocument.Bookmarks.Add sBkmName, rngCheck
rngCheck.Font.Name = sFontName
ElseIf Asc(rngCheck.Text) = iChecked Then
rngCheck.Text = Chr(iNotChecked)
rngCheck.Font.Name = sFontName
ActiveDocument.Bookmarks.Add sBkmName, rngCheck
End If
End Sub

How to stop a DataGridView removing columns on subsequent form loads? [duplicate]

I have a custom form which is open as Form.ShowDialog()
This form acts as a confirmation form. It asks a question whether you want to accept or decline the previously entered input in ComboBox & TextBox.
If you click OK, the input is saved into Excel File.
If you click Cancel, the input is not saved.
The problem I am having is that:
When you click cancel. The form.ShowDialog() is closed. (Which is fine.)
But when the form.ShowDialog() is open again. It retains the focus on the Cancel Button. So if you try to confirm the entry with "Enter" key, you cancel it instead.
My question is. Why does the Form.ShowDialog() retain the focus on the buttons after closing?
The Form.ShowDialog() has accept button "OK" [tabindex = 1], and cancel button "Cancel" [tabindex = 2] which are set to Enter key, and Esc key.
(To note again)The focus of the buttons remains after closing the form.
The portion of the code using the Dialog:
ElseIf ComboBoxBP.SelectedItem = ComboBoxBP.SelectedItem And TextBoxBP.Text = TextBoxBP.Text Then
form.Label1.Text = ComboBoxBP.SelectedItem
form.Label2.Text = TextBoxBP.Text
form.ShowDialog()
If form.DialogResult = Windows.Forms.DialogResult.Yes Then
SiE()
ElseIf form.DialogResult = Windows.Forms.DialogResult.No Then
LabelBPBot.Text = "Canceled."
End If
End If
When you use .ShowDialog() closing the form does not dispose of it as with a normal form. This is because once a Dialog "closes" it actually just hides so we can get info from it before it actually goes away.
The second issue is that forms are classes (it says so at the top of every one of them:)
Public Class Form1
...
So, instances of them should be created. VB allows Form1.Show or Form1.ShowDialog() to use a "default instance" and it is a shame that it does.
Combine these 2 tidbits and what you have is a case where the form you showed last time is still around in the same state as when you last used it, including the last focused control. You are only using a "fresh copy" of the form the first time, after that, you are just reusing the old instance. Remedy:
Using Dlg As New Form1 ' form1 is the class, dlg is the instance
... do stuff
Dim res As DialogResult = Dlg.ShowDialog()
If res = Windows.Forms.DialogResult.OK Then
'... do stuff
End If
End Using ' dispose of Dlg
Eventually, you will run into similar issues using the default instance of the other forms (LForm.Show). Just Say No to Default Form instances.

Print rdlc report without viewing print dialogue box

I have am writing a POS application, which requires to print invoice very often.
I need to send it directly to printer instead of viewing the print dialogue. Using Reportviewer_renderingcomplete, I can avoid seeing the report but I do not know how to avoid seeing the print dialogue box and print report without user intervention?
Thanks a lot.
Here is how you can do it:
Dim m_currentPageIndex As Integer
Private m_streams As IList(Of Stream)
Dim report As New LocalReport()
report.DataSources.Add(New ReportDataSource("testData", reportData.Tables(0)))
report.ReportEmbeddedResource = "ReportsLibrary.rptTestData.rdlc"
Dim deviceInfo As String = "<DeviceInfo><OutputFormat>EMF</OutputFormat><PageWidth>8.5in</PageWidth><PageHeight>11in</PageHeight><MarginTop>0.25in</MarginTop><MarginLeft>0.25in</MarginLeft><MarginRight>0.25in</MarginRight><MarginBottom>0.25in</MarginBottom></DeviceInfo>"
Dim warnings As Warning()
m_streams = New List(Of Stream)()
report.Render("Image", deviceInfo, CreateStream, warnings)
For Each stream As Stream In m_streams
stream.Position = 0
Next
Dim printDoc As New PrintDocument()
printDoc.PrinterSettings.PrinterName = "<your default printer name>"
Dim ps As New PrinterSettings()
ps.PrinterName = printDoc.PrinterSettings.PrinterName
printDoc.PrinterSettings = ps
printDoc.PrintPage += New PrintPageEventHandler(PrintPage)
m_currentPageIndex = 0
printDoc.Print()
Where PrintPage defined as follows:
' Handler for PrintPageEvents
Private Sub PrintPage(sender As Object, ev As PrintPageEventArgs)
Dim pageImage As New Metafile(m_streams(m_currentPageIndex))
' Adjust rectangular area with printer margins.
Dim adjustedRect As New Rectangle(ev.PageBounds.Left - CInt(ev.PageSettings.HardMarginX), ev.PageBounds.Top - CInt(ev.PageSettings.HardMarginY), ev.PageBounds.Width, ev.PageBounds.Height)
' Draw a white background for the report
ev.Graphics.FillRectangle(Brushes.White, adjustedRect)
' Draw the report content
ev.Graphics.DrawImage(pageImage, adjustedRect)
' Prepare for the next page. Make sure we haven't hit the end.
m_currentPageIndex += 1
ev.HasMorePages = (m_currentPageIndex < m_streams.Count)
End Sub
This is an interesting walkthrough by Microsoft: Printing a Local Report without Preview.
It's a different approach from yours because it prints directly a report without using ReportViewer and RenderingComplete event.
In order to not display PrintDialog box you must set printDoc.PrinterSettings.PrinterName with your default printer name.
Maybe you can store this value in a user configuration file.
It is actually far more simple than you would have imagined.
Within your form, include a "PrintDocument" component from the Toolbox.
Within your code behind, you will want to call the following method on your newly added component.
PrintDoc.Print()
The documentations state that the Print() "Starts the document's printing process". It will automatically begin printing the default set printer.
As tezzo mentioned, to set the Printer manually you can use the following snippet:
PrintDoc.PrinterSettings.PrinterName = "YourPrinterNameHere"
PrintDoc.PrinterSettings.PrinterName "gets or sets the name of the printer to use" as according to documentation. And if you need any further help, check out this video.
Please note however that video does not mention how to print "silently". It is just a good reference for beginners to see how the Print Components work together.