Buy Me a Coffee

Buy Me a Coffee!

Sunday, September 23, 2012

Closing a document and loading another

One thing that I never found the right set of keywords to bring up in a set of search results is closing a loaded document and opening another within an embedded Visio control.  I am not sure if this is the correct way, or just a hack, but here is how I was able to achieve the results I wanted.

The method I ended up using was simplicity itself, once I figured it out.  Dispose of the control and create and bind a new one.  Simple right?  Here is the full code for the class:

public partial class MainWindow : Window
{
private AxDrawingControl visioControl;
private Visio.Document visioStencil;
private Visio.Documents visioDocs;
const string documentOne = @"c:\temp\TestDrawing.vsd";
const string documentTwo = @"c:\temp\TestDrawing2.vsd";
const string stencilOne = @"c:\temp\Cake.vss";

public MainWindow()
{
InitializeComponent();
SetupVisioControl();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
LoadDocument(documentOne);
}

private void button1_Click(object sender, RoutedEventArgs e)
{
visioControl.Dispose();
SetupVisioControl();
LoadDocument(documentTwo);
}

private void SetupVisioControl()
{
visioControl = new AxDrawingControl();
this.windowsFormsHost1.Child = this.visioControl;
}

private void LoadDocument(string document)
{
visioControl.Src = document;
visioDocs =
visioControl.Document.Pages.Document.Application.Documents;
visioStencil =
visioDocs.OpenEx(stencilOne, (short)Visio.VisOpenSaveArgs.visOpenDocked);
}
}

When I tried to simply use the close method on the individual documents as follows:


foreach (Visio.Document document in visioDocs)
{
document.Saved = true;
document.Close();
}

I consistently received a ComException on the document.close() call: This operation cannot be performed while doing in-place editing.

Saturday, May 26, 2012

WPF Browser Application–Visio Automation 1

Opening existing Visio documents is fun and all, but we need to go a little farther to really start having fun.  Let’s start with the basic setup from the first article.  Build a project, add your controls and references, and then fill in the Page_Loaded method with new code.

1)  Start with creating a new blank document by calling the Add method:

visioControl.Document.Pages.Document.Application.Documents.Add("");

2)  Get a reference to your new document:


Visio.Documents visioDocs =
visioControl.Document.Pages.Document.Application.Documents;

3)  Open up your stencil library (I am using a custom, remote one, it works similarly with standard, local ones):


Visio.Document visioStencil =
visioDocs.OpenEx(@"http://smithmier.com/Visio/NewCake.vss",
(short)Microsoft.Office.Interop.Visio.VisOpenSaveArgs.visOpenDocked);

4)  Get a reference to the currently active page:


Visio.Page visioPage =
visioControl.Document.Pages.Document.Application.ActivePage;


5)  Choose your shape from the Stencil:


Visio.Master visioShapeMaster = visioStencil.Masters.get_ItemU(@"Cake");

6)  Drop the shape on the page, and get a reference to the new instance:


Visio.Shape visioShape = visioPage.Drop(visioShapeMaster, 4.25, 5.5);

7)  Then finally we add some text to the shape to make it interesting:


visioShape.Text = @"Cake";

Source:  VisioWPF2.zip

Tuesday, May 8, 2012

WPF Browser Application–Visio Viewer

I decided to follow up my previous article on Embedding Visio in a WPF Browser Application by taking a look at what can be done with the Visio Viewer.  Let’s start out like we did before with a WPF Browser Application:
--New Project Image

and add your reference to the WindowsFormsIntegration part:
--Add Reference Image
and open up a Visual Studio Command Prompt (2010) and make your Interop assembly, this time from the VVIEWER.DLL (I found mine in C:\Program Files (x86)\Microsoft Office\Office14) using the command:
aximp VVIEWER.DLL
This time, two dlls are created: AxVisioViewer.dll and VisioViewer.dll.  We are only going to be using AxVisioViewer.dll at this time, so add your reference:
--Add Reference Image
You then drop your WindowsFormsHost on the panel or add the following in the xaml:
<WindowsFormsHost HorizontalAlignment="Stretch" Name="windowsFormsHost1" VerticalAlignment="Stretch" />

Add a line to your class for an instance of the AxViewer:

private AxViewer visioControl = new AxViewer();

and then update the constructor for the page to add the control to the WindowsFormsHost:


this.windowsFormsHost1.Child = this.visioControl;


add an event handler for the page loaded event and drop in a line to load your Visio document:

this.visioControl.SRC = @"http://smithmier.com/Visio/TestDrawing.vsd";

and finally, update your project security to a Full Trust Application on the solution properties screen:

--FullTrust

Notice the difference?  Go ahead, look back.  I will wait.

Find them?  AxDrawingControl becomes AxViewer and .Src becomes .SRC.  That is all.

Of course, there are many other things that changed, but in the very simple example code it isn’t apparent.  The two main differences for end users is that they won’t need Visio installed to view the document with this version, and they won’t be able to alter the document in this version.  I will go through the changes in the object model and control available in future posts.

Source code: VisioViewerWPF.zip

Thursday, May 3, 2012

WPF Browser Application

Why would you want to do a WPF application in a browser?  Isn’t that what Silverlight is for, letting you do XAML on the Web?  But what if you want to embed something sinister like Visio in a web page?  Will Silverlight let you do that?  No!  At least I don’t think so, If you know how to do it, please let me know, but for the purposes of this blog post, please play along.  Now, to get started, let’s open up a new Visual Studio WPF Browser Application:

First we need to add a reference to the WindowsFormsIntegration part:

Next, we need to get an Interop assembly for the Visio OCX control (AxInterop.Microsoft.Office.Interop.VisOcx).  The prevailing wisdom on the web is to open up a WinForm project and drop a Visio control on the surface to have Visual Studio automatically generate the DLL for us.  I never really like using a hammer to put in screws, so I dug around a little bit and found that aximp is the tool that Microsoft intends you to use for this little task.  So, find your copy of VISOCX.DLL (mine was in C:\Program Files (x86)\Microsoft Office\Office14) and run the following command:
aximp VISOCX.DLL
to create your very own interop assembly.  The one creates is named AxVisOcx.dll by default, but it has the same content as the one generated by Visual Studio.  Add a reference to it in your Visual Studio project by using the Browse tab:

You then drop your WindowsFormsHost on the panel or add the following in the xaml:
<WindowsFormsHost HorizontalAlignment="Stretch" Name="windowsFormsHost1" VerticalAlignment="Stretch" />

Add a line to your class for an instance of the AxDrawingControl:

private AxDrawingControl visioControl = new AxDrawingControl();

and then update the constructor for the page to add the control to the WindowsFormsHost:

this.windowsFormsHost1.Child = this.visioControl;

add an event handler for the page loaded event and drop in a line to load your Visio document:

this.visioControl.Src = @"http://smithmier.com/Visio/TestDrawing.vsd";

and finally, update your project security to a Full Trust Application on the solution properties screen:



Source code: VisioWPF.zip

Saturday, February 25, 2012

A little Async problem

Hello again.  I am going to attempt (yet again) to start a blog and keep updating it.  I have found in the past that I quickly run out of topics if I narrow the focus too much.  I also don’t want to blog about what I had for lunch each day.  This is my latest attempt at finding the balance.  C# is what I code in, so that is what I will write about.  Thanks for watching!
Last night I solved a problem that had been bugging me for a week or more.  It has to do with this code:



 public void GetResultsAsync<T>(RestRequest request, 
		 Action<T> callback)
 {
	 var restCallback = new RestCallback(
		 (req, resp, obj) =>
			 {
				 callback(GetResults<T>(req));
			 }
		 );
	 _oauth.BeginRequest(request, restCallback);

 }

 public T GetResults<T>(RestRequest request)
 {
	 var response = Request(request);
	 var result = GetResponse<T>(
		   response.ContentStream);

	 if (result.Status != "ok")
	 {
		 throw new GeekListException(
				 result.Status, result.Error);
	 }

	 return result.Data;
 }
See the problem?  If you do, you are much better at this than I am.  I am just getting into Asynchronous patterns as part of the Windows Phone coding that I am doing in my spare time, so some of this is new to me.  I still don’t fully grok binding and template usage on the phone with async data sources, but I am getting there.

Want a hint?  My unit tests are failing for any async method that creates a new item.  Curious isn’t it?  All of the retrieval tests work fine, just not the creates.  Take a moment to look back at the code if you want, I will wait. 

How do you debug something like this?  Fiddler is my tool of choice, and I quickly discovered that I was making two calls to the web site for each async call:

and the second one was failing because it was trying to insert duplicate data.  Have you figured it out yet?  Take another look back at the code.  Isn’t it obvious?  Well, it wasn’t to me.  I spent a couple of days banging my head against hard vertical objects like walls, doors, trees, etc. 

I decided that perhaps the OAuth library that I was using was mis-behaving (blame someone else) so I grabbed a fork from GitHub and started tracing code. 


This won’t take long…I am sure there is just a misplaced…wait, this looks good.  Gack, this is complex!  Oh, that’s right, that is why I am using a library rather than rolling my own. 

I thought that it must be some type of re-try issue, so I updated the GetResultsAsync method to decorate the request with all sorts of time and retry related stuff:
public void GetResultsAsync<T>(   
        Action<T> callback,    
        RestRequest request)   
{   
    var restCallback = new RestCallback(   
        (req, resp, obj) => callback(   
                GetResults<T>(resp)));   
    request.Timeout =    
        new TimeSpan(0, 0, 5);  
     request.RetryPolicy =   
         new Hammock.Retries.RetryPolicy();  
     request.RetryPolicy.RetryCount = 0;  
     _oauth.BeginRequest(request,   
         restCallback);  
}

but no amount of request tweaking would keep the second call from showing up in Fiddler.

Finally, in desperation, I even opened a question on StackOverflow (http://stackoverflow.com/questions/9372760/hammock-async-calls-appear-to-be-duplicated, yes, I deleted it once I found my problem), which as a long time lurker, was admitting defeat in an epic way.  I showed code, the screen shots from above, tagged it with appropriate tags, and waited.

And then no-one swooped in to save the day.  Ouch, only 5 views of the question in as many days and no comments or answers?  *sigh* 


Perhaps if I build a test project and provide a more complete solution?  Is there an OAuth service that I can test against?  http://term.ie/oauth/example/ looks good.  Let me just make a new project and do some basic authentication…

And then, while building an isolated test project (I use WinForms for these because I like to push buttons and see stuff happen) I found my error.  Wow, was it

Ok, last chance, have you found my problem?  I am about to show the refactored code, and I don’t want to ruin it for anyone playing the home game. 

Ok, you were warned, here it is:



public void GetResultsAsync<T>(Action<T> callback, RestRequest request)
{
	var restCallback = new RestCallback(
		(req, resp, obj) => callback(GetResults<T>(resp)));
	_oauth.BeginRequest(request, restCallback);
}

public T GetResults<T>(RestRequest request)
{
	var response = Request(request);

	return GetResults<T>(response);
}


public T GetResults<T>(RestResponse response)
{
	var result = GetResponse<T>(response.ContentStream);

	if (result.Status != "ok")
	{
		throw new GeekListException(result.Status, result.Error);
	}

	return result.Data;
}

There, see it?  It is subtle until it smacks you in the face.  I was doing a synchronous call in the middle of my asynchronous handler.  Yes I was, look again.  That is the whole reason I had listed the GetResults method to begin with, show dependencies and all.  *sigh* 

I haven’t thought through all of this fully yet, so I am sure that the above code breaks a ton of pattern rules, and has a code smell foul enough to clear a room full of PHP coders, but it works.  I will try and get back to this if I refactor it, but this is good enough for now.

Thanks for listening!