Saturday, February 25, 2006

Word Action Pane with VSTO in C# 2005

I have created a Word Action pane with a tab control contained within the user control. In order to force the user control to strech to fill the action pane space you need the following code:

private QuoteBuilder qb_actionpane = new QuoteBuilder ();

private void ThisDocument_Startup (object sender, System.EventArgs e)

{

qb_actionpane.Dock = DockStyle.Fill;

this.ActionsPane.StackOrder = Microsoft.Office.Tools.StackStyle.None;

this.ActionsPane.Controls.Add (qb_actionpane);

}


The problem is that VS2005 does not display the .Dock property so you have to set it yourself in code. In addition you need the following code

this.ActionsPane.StackOrder = Microsoft.Office.Tools.StackStyle.None;

Without this the user control does not fill the available space.

Thursday, February 16, 2006

C# - Fill TreeView with SQL data

Here is some c# code to fill a treeview with hierarchal data from an sql table. The SQL table looks like this:-



Each item in the database has a pointer to it's parent (which can be null for top level items). The DisplayOrder field is used to alter the display order of items at the same level. NodeType should be "Node" for a nodes, anything else is assumed to be a "document".

The tree is displayed like this:-


Here is the code

private void LoadTreeview ()

{

// This code fills a DataTable with an SQL Query

DataTable table = DatabaseUtility.ExecuteDataTable (

new SqlConnectionSettings.Default.SQL_DSN), (Properties.

"select ID, ParentID, DisplayOrder, NodeType, NodeText from TableName"

);

// Fill the TreeView with database data. Use null

// as parentid for top level

AddKids (null, "ParentID is null", "DisplayOrder", table);

}

private void AddKids (string parentid, string filter, string sort, DataTable table)

{

DataRow[] foundRows = table.Select (filter, sort);

if (foundRows.Length == 0)

return;

// Get TreeNode of parent using Find which looks in the name

// property of each node. true itterates all children

TreeNode[] parentNode = treeView1.Nodes.Find (parentid, true);

if (parentid != null)

if (parentNode.Length == 0)

return;

// Add each row to tree

for (int i = 0; i <= foundRows.GetUpperBound (0); i++)

{

string nodetype = foundRows[i]["NodeType"].ToString ();

string nodetext = foundRows[i]["NodeText"].ToString ();

string nodeid = foundRows[i]["ID"].ToString ();

TreeNode node = new TreeNode ();

node.Text = nodetext;

node.Name = nodeid; // This is critical as the Find method searches the Name property

if (parentid == null)

treeView1.Nodes.Add (node); // Top Level

else

parentNode[0].Nodes.Add (node); // Add children under parent

// Itterate into any nodes

if (nodetype.ToLower () == "node")

AddKids (nodeid, "ParentID=" + nodeid, sort, table);

}

}


The trick here is to use the nodetype.Name to hold a unique ID of each item. The treeview.Nodes.Find("xxx") command is the olny way you can search the entire tree (including children) and it searches the .Name property only.

Using ASP.NET 2.0 GridView Template Controls

I'm using a GridView control on an ASP.NET 2.0 page. I have added some templated columns so the grid looks like this:-

When the Test button is pressed I want to get the values in the TextBoxes. There are two options:-

Option 1
Set the CommandArgument of the Test button to hold a value indicating the row number. You need to add the following to the Test button's HTML definition

CommandArgument='<%# Container.DataItemIndex %>'


IE7B2 does not render the text above correctly, Firefox is OK, it should look like this :

Then you can get the Row and TextBox contents using this code

protected void GridView1_RowCommand (object sender, GridViewCommandEventArgs e)

{

if (e.CommandName.ToLower () == "test")

{

int rowindex = int.Parse (e.CommandArgument.ToString ());

GridViewRow row1 = GridView1.Rows[rowindex];

TextBox tb_percent1 = row1.FindControl ("TextBox1") as TextBox;

TextBox tb_value1 = row1.FindControl ("TextBox2") as TextBox;

TextBox tb_month1 = row1.FindControl ("TextBox3") as TextBox;

TextBox tb_year1 = row1.FindControl ("TextBox4") as TextBox;


Option 2

You can use the following code. With this option you do not need to set the CommandArgument on the button.

protected void GridView1_RowCommand (object sender, GridViewCommandEventArgs e)

{

if (e.CommandName.ToLower () == "test")

{

GridViewRow row2 = (GridViewRow) ((Control) e.CommandSource).Parent.Parent;

TextBox tb_percent2 = row2.FindControl ("TextBox1") as TextBox;

TextBox tb_value2 = row2.FindControl ("TextBox2") as TextBox;

TextBox tb_month2 = row2.FindControl ("TextBox3") as TextBox;

TextBox tb_year2 = row2.FindControl ("TextBox4") as TextBox;

Wednesday, February 08, 2006

VS2005 Snippets

How do I fix this problem with VS2005 snippets?

Notice application and Visual c#2005 are in there twice.

Ambiguous match found error in precompiled ASP.NET page

I upgraded an ASP.NET 1.1 project to 2.0 and precompiled it before uploading it to my production web server. Unfortunately one of the pages refused to work (I thought pre-compilation was supposed to find these problems!).

This is the error I was getting when I viewed the problem page:-

Parser Error Message: Ambiguous match found.

It turns out that Visual Studio 2005 creates hidden field declarations for all controls inserted into a page. For some reason my old code had the following field declaration:-

18 namespace ITM

19 {

20 ///

21 /// Summary description for WebForm1.

22 ///

23 public partial class WebForm1 : System.Web.UI.Page

24 {

25 protected System.Web.UI.HtmlControls.HtmlInputFile file2;


Because my code had a declaration for file2 it clashed with the declaration that VS2005 has created. This results in a project that compiles without any problem but refuses to run!!! (The project woks fine in dynamic compilation mode)

This bug has already been reported to Microsoft as bug FDBK38831 but it is shown as "Won't Fix" because VS2005 cannot detect the error. It would be better if the error message was a little clearer!

If you have this problem make sure you do not declare any variables with the same name as any of your controls.

Monday, February 06, 2006

Upgrade Asp.net app to V2.0

I upgraded an asp.net V1.1 app to V2.0 and VS2005 automatically converted my global.aspx.cs file so all the code is located in the App_Code folder. In order to use any of the static functions in the global class it is necessary to add "using Your_Global_Namespace;" to any class that uses any of the global functions.

This is required because any new web page generated by VS2005 does not seem to place the page class inside your global namespace. Something to do with partial classes?

VS2003 code generated for a new web page
namespace ARJ
{
public partial class BlahBlah : System.Web.UI.Page
{
}
}

VS2005 code generated for a new web page
public partial class BlahBlah : System.Web.UI.Page
{
}

you therefore need to add

using ARJ;

to any VS2005 web page that uses the any of the global functions.

Thursday, February 02, 2006

C# How to load an icon from an embedded resource

This is how to load an Icon from an embedded resource and then use it to change a task bar notification icon.

Firstly embed the icons as a resource. Don't forget to change the Build Action of each icon to "Embedded Resource"

Declare these variables

private System.Drawing.Icon icnNormal;
private System.Drawing.Icon icnAlert;

Put this in your Form_Load() method

System.IO.Stream st;
System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly ();
st = a.GetManifestResourceStream ("{{{YourAppName}}}.Resources.App.ico");
icnNormal = new System.Drawing.Icon (st);
st = a.GetManifestResourceStream ("{{{YourAppName}}}.Resources.arrow-up_32.ico");
icnAlert = new System.Drawing.Icon (st);

Replace {{{YourAppName}}} with the name of your application

To use the icon

notifyIcon1.Icon = icnAlert;