Search This Blog

Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Monday, October 26, 2015

How to efficently update WPF MainWindow from an async task

Is this an acceptable approach to update WPF MainWindow from an async task, using events thrown from a public static class?
In MainWindow.cs, I subscribe to UI.TaskCompleted event In UI.cs, I subscribe to AsyncTaskActions.TaskCompleted event.
Using this pattern, AsyncTaskActions.TaskCompleted is raised with a async task is completed. UI catch the event and raise UI.TaskCompleted. This way, the event is catch in MainWindow code where I can use Displacher.Invoke to refresh the displayed page. The end result is I get a page refresh when a task is completed and the task still runs asychronously.
Application design summary:
MainWindow: main window which can have several different page classes in content area within the main window.
Common.cs public static class contains a number of common methods through the UI in the application.
AsyncTaskActions.cs - class with a number of async common methods (ie download file)



Wednesday, February 5, 2014

Helpful ASP.NET forms authenication and session timeout article


From Adam Tuliper's Development Tips

What happens when user session timeouts before Form authenication does?

http://completedevelopment.blogspot.com/2009/12/caution-with-using-sessiontimeout-and.html

Modifield code from Adam's article:

Add the following code to global.asax to reroute request to login if session has expired:

protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            //Only access session state if it is available
            if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState)
            {
                //If we are authenticated AND we dont have a session here.. redirect to login page.
                HttpCookie authenticationCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
                if (authenticationCookie != null)
                {
                    FormsAuthenticationTicket authenticationTicket = FormsAuthentication.Decrypt(authenticationCookie.Value);
                    if (authenticationTicket != null && !authenticationTicket.Expired)
                    {
                        if (Session["username"] == null)
                        {
                            //This means for some reason the session expired before the authentication ticket. Force a login.
                            FormsAuthentication.SignOut();
                            Response.Redirect(FormsAuthentication.LoginUrl, true);
                            return;
                        }
                    }
                }
            }
        }

Saturday, March 16, 2013

Path.Combine() - this is just stupid....

In my DRC project, I found a bug specifically caused by incorrect file path.

My approach was the Base folder path in my app.config / Settings and then use relative paths for all the resources  I need to store in a database.  Seems like a solid plan.   Actually, been using this approach for 10+ years now... what went wrong?

Recently, I've been using Resharper tool to tighten up my code.  During my review of the code, I found where I had some manually concatenated paths using string.Format().  With an eye to porting my application to iOS or Android using Mono, I thought building paths from simple strings simply won't do.  Better to use System.IO.Path.Combine() right?

Wrong!  After converting this code to use Path.Combine() errors occurred.  Impossible I thought, the paths are correct.  I found this issue on StackOverflow:


Why Does Path.Combine not properly concatenate filenames that start with Path.DirectorySeparatorChar

In my testing I found this:

Path path + subfolder + file name

System.IO.Path.Combine(@"C:\DRC_Data","USA","48cnty.dbf")
"C:\\DRC_Data\\USA\\48cnty.dbf"   - PASS


System.IO.Path.Combine(@"C:\DRC_Data\","USA","48cnty.dbf")
"C:\\DRC_Data\\USA\\48cnty.dbf" + PASS


System.IO.Path.Combine(@"C:\DRC_Data",@"USA",@"\48cnty.dbf")
"\\48cnty.dbf" - FAIL



System.IO.Path.Combine(@"C:\DRC_Data\",@"\USA","48cnty.dbf")
"\\USA\\48cnty.dbf" - FAIL


System.IO.Path.Combine(@"C:\DRC_Data\",@"USA",@"\48cnty.dbf")
"\\48cnty.dbf" = FAIL


System.IO.Path.Combine(@"C:\DRC_Data\",@"\USA\",@"48cnty.dbf")
"\\USA\\48cnty.dbf" - FAIL

Now, I'm not going to declare Path.Combine() useless for building paths with relative elements but there needs to a an option set for Path.Combine() does not assume every element that starts with a backslash as a start of a root path.

Path.Combine() works as per spec but it's not what I would have expected either.
Bottom line, it is a helper function that should be more helpful!










 


Saturday, December 29, 2012

RDLC Basics


So less than 6 hrs of time invested and I have basic RDLC reporting working for data displayed in a table / grid.  Also created several multi-column reports.

So here is my basic approach:

My data source is a MS Access MDB file but this would work for SQL server just as easy. Simply a different connection string.

Step #1 - Create a visual dataset with table adapters that can be bound to a report.



Step #2 Create basic RDLC report without using the wizard.

  1.  Add new item, select reporting template, select Report.
  2. In report data panel, select new dataset
  3. Select data source 
  4. Select table adapter
  5. Add table / grid to body of the report.
  6. Assign columns in the table / grid to fields from the tableAdapter field list
  7. Right-click in the report designer below the report body and add page header or page footer as needed.
  8. Add Report name, execution time, and page number from built-in fields
Step #3 Fetch data for report and return it as a data table
Here is  my design approach.  I only use table adapters to bind fields in the designer.  At runtime, I like to manually fetch the data and add it to report data source.  I do this so I can re-use report design and pass slightly different data sets to the same report.  This is similar to the approach I used 10 year ago with MS Access reports.  Not for everyone but it works for me.

I create a function where I can return the data I want by passing in the report name.


public static DataTable GetReportData(string reportName, string MDBfile)
{
try
{
EnterProc(MethodBase.GetCurrentMethod());
string sql = null;
DataTable table = null;
switch (reportName)
{
case "":
break;
case "CollectionSummaryByYear":
sql = "SELECT [Year], COUNT([Year]) AS SpecimenCount FROM tblMineral_Collection WHERE (Len([Year]) > 0) GROUP BY [Year]";
break;
case "FossilLabel_SmallCabinet":
case "FossilLabel_Thumbnail":
sql = "SELECT tblFossils.ID_Text, tblFossils.CommonName, tblFossils.ProperName, tblFossils.RockFormation, tblFossils.RockAge, tblFossils.Location, tblFossils.County, tblFossils.City, lstStates.State, lstCountries.Country, Str([tblFossils].[Year]) AS strYear FROM (tblFossils LEFT JOIN lstCountries ON tblFossils.CountryID = lstCountries.ID) LEFT JOIN lstStates ON (tblFossils.StateID = lstStates.ID) AND (tblFossils.CountryID = lstStates.CountryID);";                        
break;
case "MineralLabel_Cabinet":
case "MineralLabel_SmallCabinet":
case "MineralLabel_Micromount":
case "MineralLabel_Thumbnail":
sql = "SELECT tblMineral_Collection.ID_Text, tblMineral_Collection.Variety, tblMineral_Collection.Mineral_Name, tblMineral_Collection.Mine, tblMineral_Collection.City, tblMineral_Collection.County, lstStates.State, lstCountries.Country, Str([tblMineral_Collection].[Year]) AS StrYear, tblMinerals.Formula_1, tblMinerals.Formula_2 FROM (((LabelQueue INNER JOIN tblMineral_Collection ON LabelQueue.Specimen_ID = tblMineral_Collection.Specimen_ID) LEFT JOIN lstCountries ON tblMineral_Collection.CountryID = lstCountries.ID) LEFT JOIN lstStates ON (tblMineral_Collection.CountryID = lstStates.CountryID) AND (tblMineral_Collection.StateID = lstStates.ID)) LEFT JOIN tblMinerals ON tblMineral_Collection.Mineral_Name = tblMinerals.Mineral";
break;
case "SpeciesList":
sql = "SELECT tblMineral_Collection.Mineral_Name, Count(tblMineral_Collection.Mineral_Name) AS SpecimenCount FROM  tblMineral_Collection WHERE LEN(Mineral_Name)>0 GROUP BY tblMineral_Collection.Mineral_Name";
break;
}
 
if (!string.IsNullOrEmpty(sql))
{
table = TableFromMdb(MDBfile, sql);
}
ExitProc(MethodBase.GetCurrentMethod());
return table;
 
}
catch (Exception ex)
{
ErrorLog(ex);
return null;
}

The only trick to this approach is to pass in the data using name of dataset originally used to setup report.

var rds = new ReportDataSource("DataSet1", args.ReportData);
var report = new LocalReport
{
ReportEmbeddedResource = string.Format("DRC.RDLC.{0}.rdlc", args.ReportName)
};
report.DataSources.Add(rds);



Friday, December 28, 2012

Finally Replacing CrystalReports

I've had a long hate-hate relationship with crystal reports.  Latest version of Crystal Reports via SAP is a 72 MB install!?! Why....  CrystalReport 2008 was only 17 MB.  Leave it to SAP to take a poor solution and make it worse.

So, I've been on a quest to replace crystal Reports.  In VS 2010, I've found a workable client side reporting solution in RDLC.  Now, I know its going to be an uphill battle to produce Avery style labels with RDLC but I'm going uphill 75MB lighter.

The real motivation for this reporting switch is my next version of Digital Rockhound's Companion software is going to be a download users can buy.  I'll trimmed down the files my software uses.  I'm ditching my street level arcview shapefiles dated circa 1995 for Google/Bing/OSM online maps.  Last piece is really the reporting engine.

In a little under 3 hours, I was able to add in a basic grid RDLC report into DRC 3.0 and get the report to display in the report viewer, print directly to a local printer, and render to a PDF and word file formats.

Resources that helped me with RDLC reports:

Brian Hartman's code to manually print a RDLC report.  Code sample Here.

MSDN: Walkthrough: Printing a Local Report without Preview 

Get this error attempting to print a localreport without a RDLC source.
The report definition for report 'xxx' has not been specified.

A couple of useful stackoverflow posts:
Code to convert RDLC to a PDF
Code to convert RDLC to Word.

Article from dotnetsoldier blog

My code to render a simple RDLC report to a word Doc and then launch word:


var rds = new ReportDataSource("DataSet1", args.ReportData);
                        var report = new LocalReport
                            {
                                ReportEmbeddedResource = string.Format("DRC.RDLC.{0}.rdlc", args.ReportName)
                            };

                        report.DataSources.Add(rds);
                        // ReSharper disable RedundantAssignment
                        string encoding = String.Empty;
                        string mimeType = String.Empty;
                        string extension = String.Empty;
                        // ReSharper restore RedundantAssignment

                        Warning[] warnings = null;
                        string[] streamids = null;
                        string wordDocName = args.PDFFileName.ToLower().Replace(".pdf", ".doc");
                        byte[] bytes= report.Render("WORD", null, out mimeType, out encoding, out extension, out streamids, out warnings);
                        using (var fs = new FileStream(wordDocName, FileMode.Create))
                        {
                            fs.Write(bytes, 0, bytes.Length);
                        }
                        if (File.Exists(wordDocName))
                            System.Diagnostics.Process.Start(wordDocName);



//My code to print RDLC locally:

                        var rds = new ReportDataSource("DataSet1", args.ReportData);
                        var report = new LocalReport
                            {
                                ReportEmbeddedResource = string.Format("DRC.RDLC.{0}.rdlc", args.ReportName)
                            };

                        report.DataSources.Add(rds);
                        var reportPrintDoc = new ReportPrintDocument(report)
                            {
                                PrinterSettings = {PrinterName = Properties.Settings.Default.DRC_Printer}
                            };

                        reportPrintDoc.Print();


Thursday, May 24, 2012

Add date string to a file name

 string logfile = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), string.Format("RISCONVDB_{0}.LOG", DateTime.Now.ToFileTime()));

Friday, January 20, 2012

Get identity column seed values

Writing a routine to fetch identity column seed values for tables in a SQL 2008 database
Looking to import data into a database and I need to allow room when I do insert with identity_insert on

                using (SqlConnection conn = new SqlConnection(mMRISConnConfig.ConnectionString))
                {
                    string mrisSQL = @"SELECT IDENT_SEED(TABLE_NAME) AS Seed,
                               IDENT_INCR(TABLE_NAME) AS Increment,
                               IDENT_CURRENT(TABLE_NAME) AS Current_Identity,
                               TABLE_NAME
                               FROM INFORMATION_SCHEMA.TABLES
                               WHERE OBJECTPROPERTY(OBJECT_ID(TABLE_NAME), 'TableHasIdentity') = 1
                               AND TABLE_TYPE = 'BASE TABLE'
                               AND TABLE_NAME in ('W_PATIENT','W_REFERRING_PHYSICIAN','W_REFERRING_PHYSICIAN_LOCATION')";

                    conn.Open();
                    SqlCommand cmd = new SqlCommand(mrisSQL, conn);
                    SqlDataReader reader = cmd.ExecuteReader();
}

Wednesday, January 18, 2012

Using ShowHelp instead of HtmlHelp

My ongoing project is rewriting a database application I first wrote in MS Access 95 to VB6 and now into C#.
97% of the conversion is finally done except for the help file.

I am using HelpNDoc to author a chm help file and I was using the following VB6 code to open topics by topicID


Option Explicit

Public Declare Function HtmlHelp Lib "hhctrl.ocx" Alias "HtmlHelpA" _
        (ByVal hwndCaller As Long, ByVal pszFile As String, _
        ByVal uCommand As Long, ByVal dwData As Long) As Long

Global Const HH_DISPLAY_TOPIC = &H0
Global Const HH_SET_WIN_TYPE = &H4
Global Const HH_GET_WIN_TYPE = &H5
Global Const HH_GET_WIN_HANDLE = &H6

' Display string resource ID or text in a popupwin.
Global Const HH_DISPLAY_TEXT_POPUP = &HE
' Display mapped numeric value in dwdata
Global Const HH_HELP_CONTEXT = &HF
' Text pop-up help, similar to WinHelp's HELP_CONTEXTMENU
Global Const HH_TP_HELP_CONTEXTMENU = &H10
' Text pop-up help, similar to WinHelp's HELP_WM_HELP
Global Const HH_TP_HELP_WM_HELP = &H11

Calling HtmlHelp:

Private Sub cmdHelp_Click()
    Call HtmlHelp(0&, gHelpFile, HH_HELP_CONTEXT, HELP_BookWindow)
End Sub

So to keep my helpfile structure I needed to be able to open help topics by topicID in C#
Here is how to call ShowHelp using topicIDs.
(Needed to invoke ToString() on the int variable to get the value to pass as an object).


public static void OpenHelp(Form currentForm, Int32 helpTopicID)
{
            try           
            {
                System.Windows.Forms.Help.ShowHelp(currentForm, _helpFile, HelpNavigator.TopicId, helpTopicID.ToString());
            }
            catch(Exception ex)
            {
                DRCCommon.Common.ErrorLog(ex);
            }
}

Saturday, September 24, 2011

Open folder to location of a file with C#

Sometimes the simplest things are the hardest for me to remember.

Earlier I had wrote the same code for VB6


string myPath = @"C:\Users\admin\Desktop\fotos";
System.Diagnostics.Process prc = new System.Diagnostics.Process();
prc.StartInfo.FileName = myPath;
prc.Start();

Saturday, September 10, 2011

   C# code to add a column to an existing MS Access Table.

Revised  post to correct the horrible code formatting.  Sorry....



public static void AddDAOTableColumn(string MDBfile, string tableName, string ColumnName, TypeCode dataType, Int32? columnSize, bool AutoNumber)
{
try
{
 
EnterProc(System.Reflection.MethodBase.GetCurrentMethod());
dao.DBEngine DBE = new dao.DBEngine();
dao.Database DB = DBE.OpenDatabase(MDBfile, false, false, "");
 
LogValue(string.Format("Opened Database: {0}", DB.Name));
 
dao.TableDef table = DB.TableDefs[tableName];
 
LogValue(string.Format("Found Table: {0}", tableName));
 
bool bAddColumn = true;
 
if (table != null)
{
foreach (dao.Field fld in table.Fields)
{
if (fld.Name == ColumnName)
{
bAddColumn = false;
break;
}
}
}
else
bAddColumn = false;
 
LogValue(string.Format("Table.{0} exists?:{1}", ColumnName, !bAddColumn));
 
if (bAddColumn)
{
dao.DataTypeEnum columnType;
 
switch (dataType)
{
case TypeCode.Boolean:
columnType = dao.DataTypeEnum.dbBoolean;
break;
case TypeCode.DateTime:
columnType = dao.DataTypeEnum.dbDate;
break;
case TypeCode.Int16:
columnType = dao.DataTypeEnum.dbInteger;                            
break;
case TypeCode.Int32:
columnType = dao.DataTypeEnum.dbLong;                            
break;
case TypeCode.Object:
columnType = dao.DataTypeEnum.dbMemo;
columnSize = null;
break;
case TypeCode.String:
if (columnSize <= 255)
columnType = dao.DataTypeEnum.dbText;
else
{
columnType = dao.DataTypeEnum.dbMemo;
columnSize = null;
}
break;
default:
columnType = dao.DataTypeEnum.dbText;
if (columnSize == null)
columnSize = 50;
break;
}
 
dao.Field newfield = new dao.Field();
newfield.Name = ColumnName;
newfield.Type = (short)columnType;
 
if (newfield.Type == (short) dao.DataTypeEnum.dbText)
newfield.AllowZeroLength = true;
 
if (columnSize != null)
newfield.Size = Convert.ToInt32(columnSize);
 
if (AutoNumber)
newfield.Attributes = (int)dao.FieldAttributeEnum.dbAutoIncrField;
 
table.Fields.Append(newfield);
table.Fields.Refresh();
DB.TableDefs.Refresh();
 
LogValue(string.Format("Created Column: {0}", newfield.Name));
 
DB.Close();
 
table = null;
newfield = null;
DB = null;
DBE = null;
}
ExitProc(System.Reflection.MethodBase.GetCurrentMethod());
}
catch (Exception ex)
{
ErrorLog(ex);
}
}


Tuesday, August 30, 2011

Better way to debug a Windows Service

Using  conditional IF & Debugger.Launch()  to debug a windows Service better and effectively.



Sunday, August 28, 2011

C# Code to add a registry Key

Discovered that adding Registry keys is slightly more complicated using C# vs VB6...
Needed to define a user and registry security to a key change....

public static bool AddRegKey(string keyName, string valueName) { try { string user = Environment.UserDomainName + "\\" + Environment.UserName; RegistrySecurity rs = new RegistrySecurity(); rs.AddAccessRule(new RegistryAccessRule(user, RegistryRights.ReadKey | RegistryRights.Delete | RegistryRights.WriteKey | RegistryRights.ChangePermissions, InheritanceFlags.None, PropagationFlags.None, AccessControlType.Allow)); RegistryKey key = Registry.CurrentUser.OpenSubKey(sDRCRegKey,true); key.SetAccessControl(rs); key.SetValue(keyName, valueName); return true; } catch { return false; } }

Friday, November 26, 2010

Create and populate a DataTable manually.

Create and populate a DataTable manually.

DataTable table = new DataTable();
table.TableName = "SelectedMinOcc";
table.Columns.Add("ID", typeof(Int32));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("LAT", typeof(double));
table.Columns.Add("LONG", typeof(double));

foreach (DataGridViewRow row in dgvSearchResults.SelectedRows)
{
table.Rows.Add(Convert.ToInt32(row.Cells["ID"].Value)
, Convert.ToString(row.Cells["Name"].Value)
, Convert.ToDouble(row.Cells["LAT"].Value)
, Convert.ToDouble(row.Cells["LONG"].Value)
);
}

Monday, November 22, 2010

Read Windows Registry settings for VB and VBA Projects

My continuing exercise in comparative languages VB6 vs C#

Read Windows Registry settings for VB and VBA Projects

VB6
GetSetting("DRC", "Config", "DRC_CD")

C#

using Microsoft.Win32;

RegistryKey DRCKEY = Registry.CurrentUser.OpenSubKey("Software\\VB and VBA Program Settings\\DRC\\Config");
object CDPath = DRCKEY.GetValue("DRC_CD");

Thursday, October 21, 2010

Read SQL blob as byte array and save to File

This is an example that fetches a report binary stored as a blob in a SQL server table.

tbBillingPaperReport: SQL Server table where report binary is stored in column Report file.
Writes files root folder the current user document and settings folder
example:  C:\Documents and Settings\Gkindel\



using System;
using System.IO;
using System.Data.SqlClient;

private const string _SQLConnectionString = "Data Source={0};Initial Catalog={1};User ID={2};Password={3};";

SqlConnection db = new SqlConnection(string.Format(_SQLConnectionString,"ServerName", "DBName", "user", "password"));

db.Open();

SqlCommand cmd = new SqlCommand("SELECT ReportID, FileVersion, ReportName, ReportFile FROM tbBillingPaperReport", db);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataTable table = new DataTable();
adapter.Fill(table);

string savePath = Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.Personal)).ToString();                    

foreach (DataRow row in table.Rows)
{
     byte[] report = row["ReportFile"] as byte[];
     string filename = string.Format("0}\\{1}.rpt",savePath,row["ReportName"]);                           

     BinaryWriter writer = new BinaryWriter(File.Open(filename,FileMode.Create));
     writer.Write(report);
     writer.Close();
}



Thursday, July 22, 2010

A quick way to copy a table row

From http://www.devx.com/tips/Tip/32233

Because I keep looking this up. 

A Quick Way to Copy DataRow
Instead of copying DataRow column by column, the following code copies data in one line from the source to the destination row:


DataTable dtDest = new DataTable();
dtDest = dsActivity.Tables[0].Clone();
foreach(DataRow dr in dsSrc.Tables[0].Rows)
{
DataRow newRow = dtDest .NewRow();
newRow.ItemArray = dr.ItemArray;
dtDest.Rows.Add(newRow);
}

Note: The ImportRow method does the same thing, except that the RowState of source is preserved in the destination, whereas NewRow sets RowState to Added.

Saturday, April 24, 2010

Updating MS Access Linked Tables - A better solution

I added DAO 3.6 reference to my project and used the following code

Decide to go this route because MS Jet 4.0/DAO 3.6 are part of the operating system and are in Windows 2000, XP, Vista and Windows 7. They are updated by Windows Update and the security patches are applied as appropriate.




        public static void RelinkDAOTables(string MDBfile, string filepath, string sql)
        {
            DataTable linkedTables = TableFromMDB(MDBfile, sql);

            dao.DBEngine DBE =new dao.DBEngine();
            dao.Database DB = DBE.OpenDatabase(MDBfile, false, false, "");
            foreach (DataRow row in linkedTables.Rows)
            {
                dao.TableDef table = DB.TableDefs[row["Name"].ToString()];
                table.Connect = string.Format(";DATABASE={0}{1} ;TABLE={2}", filepath, row["database"],row["LinkedName"]);
                table.RefreshLink();
            }      
           
        }





Updating MS Access Linked Tables

Currently, I am trying to convert a VB6 application that uses a single MS Access database with links to 7 others  access databases using DAO linked tables to C# and ADO.NET.  For now, I am want to keep MS access for data storage.  One of the things I need is code to modify linked tables in MS Access database using C#.  Here is what I found so far:


from www.johnsoer.com -  Updating MS Access Links

    ADODB.Connection Con = new ADODB.Connection();
    ADOX.Catalog Cat = new ADOX.Catalog();
    
    Con.Open(connectionString, null, null, 0);
    Cat.ActiveConnection = Con;
    Cat.Tables[LinkedTableName].Properties["Jet OLEDB:Link Datasource"].Value = LinkedDatabaseLocation;
    Con.Close();
     

Monday, March 1, 2010

Get file name from path

I cannot remember this....

 System.IO.Path.GetFileName(filepath)

its IO.Path not IO.Directory or IO.File

Saturday, January 23, 2010

Using PropertyGrid in C#

Stupidly easy.

I am going to stop creating generic UI to display data and use the PropertyGrid as my new default to display object properties

PropertyGrid1.SelectedObject = myObject;