Adding Multiple Stencils To Same Visio Sheet - c#

I have C# code that creates a Visio Application instance, then opens some existing stencils so I can get the Shape Masters I need for my drawing. Visio 2013 changed things so I need 2 different stencils open. The issue is that I get 2 drawings open in Visio, 1 per stencil. When I build my document and save it, I can close it but there is still another empty drawing open. I also get an empty blank page in my active document where I am creating the drawing.
Visio.Application va = new Visio.Application();
va .Documents.Add(#"");
Visio.Documents vdocs = va.Documents;
const string templateNameU = "BASFLO_M.VSTX";
const string ConnectorStencilNameU = "BASFLO_M.VSSX";
const string RectangleStencilNameU = "BASIC_U.VSS";
const string stencilNameU = "CONNEC_U.VSSX";
const string connectorMasterNameU = "Dynamic Connector";
const string RectangleMasterNameU = "Rounded Rectangle";
Visio.Master connectorMaster = null;
Visio.Master rectangleMaster = null;
// open the templates we need
Visio.Document vc = vdocs.OpenEx(RectangleStencilNameU, short)Visio.VisOpenSaveArgs.visOpenDocked);
va.Documents.Add(templateNameU);
I have tried closing all the open drawings with:
foreach (Visio.Document d in va.Documents)
{
va.Documents[d.Name].Close();
}
va.ActiveDocument.Close();
but that is messy. The for loop for some reason doesn't close the active document. Is there a way to add multiple stencils to the same document and/or page so I am only working with one page? Is there a way to delete the blank page without resorting to a for loop to get the page name to delete it? I have looked through the API and don't see a way.

It looks like you are creating two documents.. i.e. the first (empty) one with va.Documents.Add("") and then the second one based on the template using va.Documents.Add(templateNameU).
If you don't want the first one, just don't create it.. Means, you can create new document, then open stencils, then draw, then close everything, like this:
var doc = va.Documents.Add(templateNameU)
var stn1 = va.Documents.Open(<first stencil>)
var stn2 = va.Documents.Open(<second stencil>)
// ... do stuff with the doc and then close everything...
doc.Close();
stn1.Close();
stn2.Close();
Am I missing something?
BTW, to get "Dynamic connector" you don't need to open the "Connector Stencil", it contains a specific dynamic connector. To get the default connector, you can just use Application.ConnectorToolDataObject
Also, you can connect shapes using shape.AutoConnect (this will also use the default connector)
Also, you don't need to open the stencil specifically actually. If it is part of the template, it will be opened automatically for you when you create a new drawing based on that template (so you can get them using Application.Documents[].
Maybe helpful? (draw 2 rectangles and connect them):
var doc = va.Documents.Add("BASICD_M.VSTX");
var stencil = va.Documents["BASIC_M.VSSX"];
var rectMaster = stencil.Masters["Rounded Rectangle"];
var rect1 = va.ActivePage.Drop(rectMaster, 1, 1);
var rect2 = va.ActivePage.Drop(rectMaster, 3, 1);
rect1.AutoConnect(rect2, Visio.VisAutoConnectDir.visAutoConnectDirNone);

Related

LibreOffice Calc C# SDK: program to insert images into cells, stuck trying to create XGraphic

Background: I'm trying to write a program to insert an image into a cell of a spreadsheet. LibreOffice recently changed how this is done, and all the samples I could find use the old method which no longer works.
Technically I know that you can't "insert" an image into a cell and that such an image is an overlay on a DrawPage that sits on top of the spreadsheet to "decorate" it.
One of the first steps in doing this (the new way) is to create an XGraphic object which contains the image. The process is to create an XGraphicProvider and call it with MediaProperties that specify the image file URL to be loaded. I have a program that is supposed to do this but the resulting XGraphic is null. The LO SDK gives pretty much no information when you do something wrong; it just doesn't work.
Here is the code I have, with all the headers removed:
// addpic
// add picture to spreadsheet - debug version
class OpenOfficeApp {
[STAThread]
static void Main(string[] args) {
bool lreadonly;
string pqfile;
string pqURL;
string pqpic;
pqfile = "file:///D:/Documents/NSexeye/ODS%20File%20Access/"+
"addpix/addpic.ods";
pqpic = "addpic2";
pqURL = pqpic+".jpg";
lreadonly = false;
Console.WriteLine("Using: "+pqfile);
// get the desktop
XComponentContext XCC = uno.util.Bootstrap.bootstrap();
XMultiComponentFactory XMCF =
(XMultiComponentFactory)XCC.getServiceManager();
XMultiServiceFactory XMSF = (XMultiServiceFactory)XCC.getServiceManager();
XComponentLoader XCL =
(XComponentLoader)XMSF.createInstance("com.sun.star.frame.Desktop");
// open the spreadsheet
PropertyValue[] pPV = new PropertyValue[2];
pPV[0] = new PropertyValue();
pPV[0].Name = "Hidden";
pPV[0].Value = new uno.Any(true);
pPV[1] = new PropertyValue();
pPV[1].Name = "ReadOnly";
if (lreadonly) pPV[1].Value = new uno.Any(true);
else pPV[1].Value = new uno.Any(false);
XComponent XCo = XCL.loadComponentFromURL(pqfile,"_blank",0,pPV);
// create graphic object containing image
object oGP = XMCF.createInstanceWithContext(
"com.sun.star.graphic.GraphicProvider",XCC);
if (oGP == null) {
Console.WriteLine("oGP is null. Aborting.");
return;
}
XGraphicProvider XGP = (XGraphicProvider)oGP;
if (XGP == null) {
Console.WriteLine("XGP is null. Aborting.");
return;
}
pPV = new PropertyValue[1];
pPV[0] = new PropertyValue();
pPV[0].Name = "URL";
pPV[0].Value = new uno.Any(pqURL);
Console.WriteLine("Creating XGraphic containing "+pqURL);
XGraphic XG = XGP.queryGraphic(pPV);
// *** XG is null here
if (XG == null) {
Console.WriteLine("XG is null. Aborting.");
return;
}
// ... lots of stuff to be added here
// save and close the spreadsheet
XModifiable XM = (XModifiable)XCo;
XM.setModified(true);
XStorable XSt = (XStorable)XCo;
XSt.store();
XCloseable XCl = (XCloseable)XCo;
XCl.close(true);
// terminate LibreOffice
// *** I want this to not terminate it if something else is open
XDesktop XD = (XDesktop)XCL;
if (XD != null) XD.terminate();
}
}
I get a null for the XGraphic, in the place indicated in the comments. I don't know if the call to create it is failing, or if one of the earlier steps of the process are incorrect.
My goal here, in addition to getting my program working, is to create a sample program showing how to add an image to a Calc spreadsheet cell, and to manipulate such images. There are a fair number of people asking questions about this and none of the examples I've found will work. I think a good working sample will be of value.
I've spent a lot of time searching for information and code samples for this, with nothing that helps. I've tried to find ways to verify the validity of the XGraphicProvider interface with no luck. I've run out of things to try.
I'm hoping someone who knows about the LibreOffice SDK can take a look and maybe see what I'm doing wrong.
Update: I figured out what I was doing wrong: I was passing a bare filename in the "URL" property to XGraphicProvider. It has to be the same format (starting with "file:///") as the spreadsheet's file name specification.
Now I'm stuck with another property problem. The XGraphic has to be specified as a parameter to the GraphicObjectShape's Graphic property, but the setPropertyValue() function requires that it be a uno.Any type. I can't figure out how to specify an interface name like XGraphic as a uno.Any.
Here is the piece of code that won't compile, complaining that it can't convert an XGraphic to a uno.Any, in the first setPropertyValue call:
// set image XGraphic
XPropertySet XPS = (XPropertySet)XS;
XPS.setPropertyValue("Graphic",XG);
XPS.setPropertyValue("Name",new uno.Any(pqpic));
XG is an XGraphic type. Using "new uno.Any(XG)" doesn't work either, giving a similar compiler error.
After trying unsuccessfully for a few hours to get the latest LO SDK up and running, let me offer some untested ideas.
First of all, here is some working Basic code, no doubt similar to what you're translating from. The important line is oShape.Graphic = oProvider.queryGraphic(Props()).
oDoc = ThisComponent
oSheet = oDoc.CurrentController.ActiveSheet
pqURL = "file:///C:/Users/JimK/Desktop/addpic.jpg"
oProvider = createUnoService("com.sun.star.graphic.GraphicProvider")
oShape = oDoc.createInstance("com.sun.star.drawing.GraphicObjectShape")
Dim Props(0) as new com.sun.star.beans.PropertyValue
Props(0).Name= "URL"
Props(0).Value = pqURL
oShape.Graphic = oProvider.queryGraphic(Props())
oCell = oSheet.getCellByPosition(5,5)
oShape.Name = oCell.AbsoluteName + "##" + Props(0).Value
oShape.Anchor = oCell
oSheet.DrawPage.add(oShape)
'Resize
w = oShape.Graphic.Size.Width
h = oShape.Graphic.Size.Height
wcl = oCell.Size.Width
hcl = oCell.Size.Height
If w<>0 and h<>0 then
oCell.String=""
Dim Size as new com.sun.star.awt.Size
Size.Width = wcl
Size.Height = h*wcl/w
If Size.Height > hcl then
Size.Width = hcl*w/h
Size.Height = hcl
Endif
oShape.setSize(Size)
oShape.setPosition(oCell.Position)
erase oShape
Else
oShape.dispose()
Endif
Now, how to translate this to C#? It looks like you may need to explicitly specify the type. In the SDK example, there are calls like this.
xFieldProp.setPropertyValue(
"Orientation",
new uno.Any(
typeof (unoidl.com.sun.star.sheet.DataPilotFieldOrientation),
unoidl.com.sun.star.sheet.DataPilotFieldOrientation.DATA ) );
So in your case, something like this:
XPS.setPropertyValue(
"Graphic"
new uno.Any(
typeof(unoidl.com.sun.star.graphic.XGraphic),
XG));
Alternatively, follow the suggestion here: set GraphicURL, which should load the image and set Graphic for you.

In FLAUI trying to Find First Child element that start with some letters

In FLAUI trying to get a reference to a child element that starts with some letters or contains some for letters.
example start with or "DOC" or contains "DOC"
what I'm trying to do is that I'm opening some office files like doc,xls, ppt.
and want to attach the file as he is open to the screen.
foreach (var file in listOfFiles)
{
if (file.Name.Contains("DOC") || file.Name.Contains("PPT") || file.Name.Contains("XLS") || file.Name.Contains("TXT"))
{
file.AsButton().Invoke();
var window = new UIA3Automation();
desktopWindow = window.GetDesktop();
desktopWindow = WaitForElement(() => desktopWindow.FindFirstChild(cr => cr.ByName("// Here want to put name that start with ... or contains ...")));
var app = FlaUI.Core.Application.Attach(desktopWindow.Properties.ProcessId);
var application = app.GetMainWindow(new UIA3Automation());
CloseingProcess(application.Name);
img
If I understood you correctly, you want to check if a file that's already open has the extension you need. Correct?
For that, you have to get a hold of the window with FlaUI and with that you can check for the property .Title on the Window class, like below:
var automation = new UIA3Automation();
var app = FlaUI.Core.Application.Attach(application.Process.Id); //attach or start application here
var window = app.GetMainWindow(automation); //Get hold
window.Title //Use the .Title or .TitleBar property to check for your extension.

c# Error with inserting more than one shape group on the slide

UPD: Maybe it helps. This is details of my Error:
System.UnauthorizedAccessException HResult=0x80070005
Message=Grouping disabled for selected shapes (Для выделенных фигур
группирование отключено). Source=FirstPPTAddIn StackTrace: at
Microsoft.Office.Interop.PowerPoint.ShapeRange.Group() at
FirstPPTAddIn.MyRibbon.OnShapeButton(IRibbonControl control) in
D:\Documents\Visual Studio
2017\Projects\FirstPPTAddIn\FirstPPTAddIn\MyRibbon.cs:line 84
I added my add-in to Exeption Settings and when I've run code for the second group set I got two additional shapes on the slide without grouping. I don't understand why the last line of code doesn't work.
I can just "copy-past" the first group set many times and make changes with them, but I need add them by button.
I used this code for grouping shapes. But it allows to put just one shape groups only. What I need to change in code for inserting unlimited shape groups on the one slide?
Part of code
PowerPoint._Application myPPT = Globals.ThisAddIn.Application;
PowerPoint.Slide curSlide = myPPT.ActiveWindow.View.Slide;
string[] myRangeArray = new string[2];
myRangeArray[0] = "shape1";
myRangeArray[1] = "shape2";
curSlide.Shapes.Range(myRangeArray).Group();
When I try to insert second shape group I have an error in the last line says System.UnauthorizedAccessException: "grouping is disabled for selected shapes".
Thanks!
That may be due to The file is already in use.Try to manually dump the powerpoint.exe after adding shape 1
An UnauthorizedAccessException can be one of the following reason:
The caller does not have the required permission.
The file is an executable file that is in use.
Path is a directory.
Path specified a read-only file.
A friend of mine solved this problem today. He add counter for the shapes in Array. The part of code below
private int count = 0;
public void OnButton(Office.IRibbonControl control)
{
var shape1Name = "shape1" + count;
var shape2Name = "shape2" + count;
...
shape1.Name = shape1Name;
shape2.Name = shape2Name;
...
string[] myRangeArray = new string[2];
myRangeArray[0] = (shape1Name);
myRangeArray[1] = (shape1Name);
curSlide.Shapes.Range(myRangeArray).Group();
count++;
}

Use White UI and FlaUI together

Can I use WhiteUI and FlaUI together in a project?
public TestStack.White.Application app = null;
public TestStack.White.UIItems.WindowItems.Window=null;
var processStartInfo = new ProcessStartInfo(#"winword.exe");
var application = Application.Launch(processStartInfo);
app=Application.Attach("winword");
FlaUI.Core.Application fpp = (FlaUI.Core.Application)app;
TestStack.White.UIItems.WindowItems.Window window = app.GetWindow("Microsoft Word");
FlaUI.Core.AutomationElements.Window fwin = (FlaUI.Core.AutomationElements.Window) Window;
Unable to cast window and application of Test Stack to FlaUI.
You would need to get the underlying AutomationElement from the White control and then create the FlaUI control using that AutomationElement. This means you will be limited to using UIAv2 only since White does not have a UIAv3 implementation.
Every UIItem in White exposed a AutomationElement property where you can get the underlying UIAv2 wrapper. Then you should be able to construct the FlaUI UIA2FrameworkAutomationElement using the AutomationElement from White as the second parameter. Then you will pass the UIA2FrameworkAutomationElementfrom FlaUI into the ComboBox from FlaUI. So it will look something like the following.
var processStartInfo = new ProcessStartInfo(#"winword.exe");
var application = Application.Launch(processStartInfo);
TestStack.White.Application app = Application.Attach("winword");
TestStack.White.UIItems.WindowItems.Window window = app.GetWindow("Microsoft Word");
TestStack.White.UIItems.ListBoxItems.ComboBox whiteCombox = window.Get<ComboBox>(SearchCriteria.ByAutomationId("MyComboBox"));
var flaUiAutomationElment = new FlaUI.UIA2.UIA2FrameworkAutomationElement(new UIA2Automation(), whiteCombox.AutomationElement);
var flaUiComboBox = new FlaUI.Core.AutomationElements.ComboBox(flaUiAutomationElment);
I would suggest just doing everything in FlaUI if at all possible.
The answer is simple: Yes, because both solutins work on the same page, and that's Automation UI.
But you gonna need to inform to FLAUI what process ID you are dealing with, like below:
var automation = new UIA3Automation(); //start new instance of FALUI
var app = FlaUI.Core.Application.Attach(application.Process.Id); //.Id its a property of you var application
var window = app.GetMainWindow(automation); //With that, FlaUI gets hold of the window
After you deal with the FLAUI, you can attach the same ID on the White and vice-versa. It's pretty straight foward.

Acrobat SDK get document path from CAcroPDDoc class object

Using,
CAcroPDDoc PdDocObj = AvDocObj.GetPDDoc() as CAcroPDDoc;
I am able to retrieve PdDocObj, but unable to find any property/method that provides me pdf file-location.
From PDDoc you can init the JSObject (set jso = PDDoc.GetJSObject) and then use something like jso.path, which will give you the device-indepentend path of the document.
OK. Following a complete working VBS example. Good Luck, Reinhard
Info = "View the path of the active doc" &vbCR &"Acrobat must be opened with an active document"
OK = MsgBox(Info, vbQuestion+vbYesNo)
if OK = vbNo then WScript.quit
Set AcroApp = CreateObject("AcroExch.App")
Set AVDoc = AcroApp.GetActiveDoc
Set PDDoc = AVDoc.GetPDDoc
set jso = PDDoc.GetJSObject
ffn = jso.path
msgbox(ffn)

Categories

Resources