Wednesday, November 16, 2011

My.Resources in C#

The equivalent of:

My.Resources

in VB.NET is:

Properties.Resources

in C#.

So,

Me.Icon = My.Resources.AppIcon

in VB.NET is equivalent to:

this.Icon = Properties.Resources.App_Icon;

in C#.

Friday, October 21, 2011

Computing RGB composite Color Value in C#

If you still have to deal with the Win32Api in C#, you may need to get the old-style RGB composite color values from a .NET Color value. The ToArgb method doesn't work like you want, so it has to be computed:

  private int ConvertColorToRGB(Color col)
    {
    return (col.R) | (col.G << 8) | (col.B << 16);
    }
 
If you are using VB.NET, it still has an RGB function to call or:

   Public Function ConvertColorToRGB(col As Color) As Integer

        Return CInt(col.R) Or (CInt(col.G) << 8) Or (CInt(col.B) << 16)

    End Function

Thursday, August 25, 2011

Updating the NUM_ROWS in USER_TABLES in Oracle

Good or bad, I use the NUM_ROWS values in the USER_TABLES table to help filter lists of tables when presenting them to the user. If I have a database and only about 25% of tables have records (and there are thousands of tables), then it is a lot nicer to only sift through the tables that do have records, and knowing how many records is even better (even if it is only an estimate). My problem is that these values don't just get updated automatically for you. You might find that they are all 0 even when there is data present. You can update all of the values with something like this:

exec dbms_stats.gather_schema_stats('mySchema', cascade=>TRUE)

A lot more info on this topic can be found at:

http://www.dba-oracle.com/concepts/tables_optimizer_statistics.htm

Monday, July 18, 2011

Creating a .CSV file in ASP.NET

I wanting to create a .CSV file from a query to SQL Server in ASP.NET. The link below has an excellent description of creating the .CSV file without having to create a temp file like I was originally planning to do. This post doesn't show how to wrap the query results up, but that is pretty simple to figure out:

http://wiki.asp.net/page.aspx/401/export-to-csv-file/

Thursday, July 14, 2011

Selecting a Folder in VB.NET

To go along with my previous post on the Open File and Save File dialogs in VB.NET, I am providing this post using FolderBrowserDialog to select a specific Directory.

Browsing to Select a Directory in VB.NET
     Dim dirDlg As New FolderBrowserDialog

dirDlg.RootFolder = Environment.SpecialFolder.MyComputer

If dirDlg.ShowDialog() = DialogResult.OK Then

' do something with the selected path
Debug.Print("Directory: " + dirDlg.SelectedPath)

Else

' the dialog was cancelled

End If


The FolderBrowsingDialog object has many options, but I have only shown the most commonly used one in the example. The RootFolder property lets you specify the directory to start browsing from. You can set this property to an explicit path (like "c:\MyData") or you can use the special directories that are defined for you:
Environment.SpecialFolder.MyDocument
Environment.SpecialFolder.MyComputer
Environment.SpecialFolder.MyPictures
Environment.SpecialFolder.Desktop

The default is Environment.SpecialFolder.MyComputer.

After the ShowDialog call returns OK, use the SelectedPath property to get the selected directory.

Selecting Files to Open or Save in VB.NET

VB.NET has come a long way from the clunky Common Dialog control of VB6 for implementing a standard dialog that will let you browse to find a file to Open or Save. Here is an example of each:

Browsing to Open a File in VB.NET
      Dim fileDlg As New OpenFileDialog

fileDlg.Filter = "CSV File (*.csv)|*.csv|txt files (*.txt)|*.txt|All files (*.*)|*.*"
fileDlg.DefaultExt = "csv"

' could be omitted to use default, or a specific dir can be given
fileDlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)

If fileDlg.ShowDialog() = DialogResult.OK Then

' Do something with the selected filename
Debug.Print(fileDlg.FileName)

Else

' the dialog was cancelled

End If

The OpenFileDialog object is used here, and I have only shown the most commonly used options. The Filter property lets you specify the which File Types will be selectable form the Open File Dialog (in a dropdown list). The value is set to a string that is a pipe (|) delimited list composed to a File Type Description and Filter Pattern. If you have more than one File Type, you can add another pipe, then another Description|Filter Pattern, and so on. If you leave the Filter property empty, then then Open File Dialog will just not have a drop down to select the File Type filter. Here are some examples:

"CSV File (*.csv)|*.csv"
"CSV File (*.csv)|*.csv|txt files (*.txt)|*.txt"
"CSV File (*.csv)|*.csv|txt files (*.txt)|*.txt|All files (*.*)|*.*"

If you are using Filter with more than one File Type specified, you can also use DefaultExt to specify which File Type to use as the default. Just specify the extension as a string (with no dot). This property also will set the default file extension to use if you don't specify it in the filename (if typed in), so this property can also be used without the Filter property being set.

The InitialDirectory property will let you define which directory to open up in. You can set this property to an explicit path (like "c:\MyData") or you can use the special directories that are defined for you, like:
Environment.SpecialFolder.MyDocument
Environment.SpecialFolder.MyComputer
Environment.SpecialFolder.MyPictures
Environment.SpecialFolder.Desktop

There is also a Title property that can be used to change the name of the Open File Dialog. In this example, it is not used and defaults to "Open File".

After the ShowDialog call returns OK, use the FileName property to get the selected filename.

Browsing to Save a File in VB.NET
   Dim fileDlg As New SaveFileDialog

fileDlg.Filter = "CSV File (*.csv)|*.csv|txt files (*.txt)|*.txt|All files (*.*)|*.*"
fileDlg.DefaultExt = "csv"

' InitialDirectory can be omitted to use default, or used to specify an explicit directory
fileDlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)

fileDlg.OverwritePrompt = True

If fileDlg.ShowDialog() = DialogResult.OK Then

' Do something with the selected filename
Debug.Print(fileDlg.FileName)

Else

' the dialog was cancelled

End If

Saving a file is similar to opening a file. You use a SaveFileDialog object instead of a OpenFileDialog object. Many of the properties work the same way as with the OpenFileDialog such as Filter, DefaultExt, and InitialDirectory. I also show OverwritePrompt set to True (which is the default). This setting will cause the dialog to prompt you when you try to save over an existing file.

After the ShowDialog call returns OK, use the FileName property to get the filename.

If you want to select a Directory instead of a file, look at this post.

Wednesday, July 13, 2011

Setting all elements of an Array to Null in C# (like with memset in C++)

I sometime find it strange that things we take for granted in C++ are hard in C#. Probably I should say hard to find the equivalent for rather than hard to do. I routinely clear out my arrays in C++ with memset (setting each item to 0). To get the equivalent in C#, you can use the Array.Clear(...) method like this:
Array.Clear(MyArray,0,MyArray.Length);
Here is a more detailed example:

http://www.dotnetperls.com/array-clear

Tuesday, July 12, 2011

Preventing Flicker with GDI+ drawing in C#

In C#, the OnPaintBackground method is called before the OnPaint event and it draws the background color for the entire view. If you are already drawing the background in the OnPaint event, then this process will cause flicker. You can override the OnPaintBackground and just do nothing in it to prevent the flicker:
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// do nothing
}

Wednesday, June 29, 2011

Script to Purge All Objects for a User in Oracle

I have to purge and reload an Oracle Database dump on a monthly basis. I have been manually deleting all of the Objects with Toad before loading the new dump. I searched for a script that would delete all of the objects. Many people suggested that you should just drop the user, but if I do this I have to add back in grants that don't get picked up by the export.

This thread on the Oracle Discussion Forum has several solutions. I am pasting the script that worked the best for me below from Massimo. There is some criticism in the thread about why he did not just use the object name in one case instead of all the If/Else conditions; however, I like this approach better, because I can easily take out something if I need to:

declare
stringa varchar2(100);

cursor cur is
select *
from user_objects;

begin
for c in cur loop
begin
stringa := '';
if c.object_type = 'VIEW' then
stringa := 'drop view ' || c.object_name;
EXECUTE immediate stringa;
elsif c.object_type = 'TABLE' then
stringa := 'drop table ' || c.object_name || ' cascade constraints';
EXECUTE immediate stringa;
elsif c.object_type = 'SEQUENCE' then
stringa := 'drop sequence ' || c.object_name;
EXECUTE immediate stringa;
elsif c.object_type = 'PACKAGE' then
stringa := 'drop package ' || c.object_name;
EXECUTE immediate stringa;
elsif c.object_type = 'TRIGGER' then
stringa := 'drop trigger ' || c.object_name;
EXECUTE immediate stringa;
elsif c.object_type = 'PROCEDURE' then
stringa := 'drop procedure ' || c.object_name;
EXECUTE immediate stringa;
elsif c.object_type = 'FUNCTION' then
stringa := 'drop function ' || c.object_name;
EXECUTE immediate stringa;
elsif c.object_type = 'SYNONYM' then
stringa := 'drop synonym ' || c.object_name;
EXECUTE immediate stringa;
elsif c.object_type = 'INDEX' then
stringa := 'drop index ' || c.object_name;
EXECUTE immediate stringa;
elsif c.object_type = 'PACKAGE BODY' then
stringa := 'drop PACKAGE BODY ' || c.object_name;
EXECUTE immediate stringa;
elsif c.object_type = 'DATABASE LINK' then
stringa := 'drop database link ' || c.object_name;
EXECUTE immediate stringa;
end if;
exception
when others then
null;
end;
end loop;
-- PURGE recyclebin

end;
/

Tuesday, June 28, 2011

Convert char[] to String in c#

If you have something like:

char [] chArray = infile.ReadChars(10);

or

char[] chArray = new char[] {'t','e','s','t'};

and you want to convert it to a String, I always (incorrectly) try:

String str = chArray.ToString();

and it doesn't work (you get "System.Char[]").

You have to say something like this:

String str = new String(chArray);

Sunday, June 26, 2011

Importing a Datapump export into Oracle with IMPDP

I never had to remember the command-line options for the old imp utility (because it prompted you for the info it needed), but with impdp, you need to know what to specify. Here is my simple example that works for me to import a Datapump export file:

impdp user/password schemas=mySchema dumpfile=myfile.dpdmp logfile=mylog.log

The schema parameter specifies which schema from the file to import.

The dumpfile parameter specifies the name of the datapump export file to import. The catch here is that the dump file location defaults to a default directory on the server (something like this):

c:\oracle\Administrator\admin\orcl\dpdump

You can change this path, but you have to create the directory in Oracle and specify it with a Directory Parameter. You have to create a directory in Oracle with something like this:

create directory MyExportDir as 'c:\exports';

Here is the detailed info for impdp on the Oracle site.

Creating a Tablespace in Oracle with SQL

I never can seem to remember the SQL to create a tablespace in Oracle. I am posting my example that I use to I can easily find it again in the future:

create tablespace MyTableSpaceName
logging
datafile 'MyTableSpaceFile.dbf'
size 32m
autoextend on
next 32m maxsize unlimited
extent management local;

Oracle Function to Read SDO_ORDINATE Values without causing Exception in .NET



Below is an Oracle function to read a specified SDO_ORDINATE value in an SDO_GEOMETRY attribute so that ODP.NET can handle them without causing an Arithmetic Overflow Exception in .NET when the Oracle NUMBER value has too many digits after the decimal place for a .NET Decimal value.

Most of this function comes from this thread on the Oracle Discussion Forum:

CREATE OR REPLACE function Get_Ordinate_Value(geom sdo_geometry, vPos number default 1) return number
is
begin

if geom is null
then
return null;
end if;

if vPos <1 or vPos >geom.sdo_ordinates.count()
then
return null;
end if;

return round(geom.sdo_ordinates(vPos ),8);
end;
/


Using the Function is something like this where I am getting the origin point and orientation vector for a 3D Oriented Point geometry:

select Get_Ordinate_Value(MyGeomAttr,1) as X,
Get_Ordinate_Value(MyGeomAttr,2) as Y,
Get_Ordinate_Value(MyGeomAttr,3) as Z,
Get_Ordinate_Value(MyGeomAttr,4) as AngleX,
Get_Ordinate_Value(MyGeomAttr,5) as AngleY,
Get_Ordinate_Value(MyGeomAttr,6) as AngleZ
from MyTable

This function is pretty simple. I first check to see if the geometry attribute is Null and return Null if it is. I found that if I did not do this, you will get a geometry attribute that is Null passed into the function and you get a "ORA-06531: Reference to uninitialized collection" and it is sometimes hard to tell where it is coming from.

Then the index is checked to see that it is in range for the SDO_ORDINATE array.

I finally use the Round function to reduce the number of digits after the decimal point to a number that the .NET Decimal type can handle.

How to use SQL to retrieve the Vertex values in an SDO_GEOMETRY Attribute

It turns out to be more complicated than you might think to simply retrieve the Vertices of an SDO_GEOMETRY attribute in Oracle Spatial using just SQL. The main problem is that this is an array of an unknown size, so the solution below is just for retrieving the Ordinate values for 1 record identified by a key and each record returned is one Ordinate in the list.

SELECT Round(COLUMN_VALUE,8) as pt
FROM TABLE( SELECT a.MyGeomAttr.SDO_ORDINATES
FROM MyTable a
WHERE MyKey=24974)


which will retrieve something like this (my example uses a 3D geometry so there are 3 value per vertex with Z being 0 in all of them):

I will go through why I did the things I did to make this work like I wanted below.

If you are using ODP.NET and you have Oracle Number values in the Ordinates that are larger than a .NET Decimal value (this is common for me), you must use Round (or truncate the value in someway) so that you don't get an Arithmetic Overflow when the Ordinate Value is loaded into a .NET decimal value. I am using the Round function to simply get 8 decimal points of precision). It turns out that the data I have uses Oriented Points and the computed vector coordinates use a large number of decimal places that .NET Decimals can't handle.

To get the Ordinate Values back as the Query results, you must use the TABLE function to convert the SDO_ORDINATES Array to records. See here for more info on the TABLE function. The key thing here is that the COLUMN_VALUE is not just me making up a name for my example, it is a keyword that lets you refer to the value the Table function returns (otherwise you can't run the results of the Table function through the Round function).

The alias "a" seems to be required or you get an error in the query.

Counting Unique (Distinct) Records with SQL

Using SQL to count all records in a table:


select count(*) from MyTable


Using SQL to count all records in a table with unique/distinct values in a particular attribute:


select count(distinct MyId) from MyTable

Wednesday, June 22, 2011

Auto-Incrementing Assembly and File version in Visual Studio

I made a post on this topic some time ago. I still find it incredible that Visual Studio (2005, 2008, 2010) doesn't provide a way to automatically increment the File Version number in an Assembly. Why is this important? To me, the Setup and Deployment project will not deliver a file if the file version is the same (even if the file is newer, different, etc.). It is very easy to forget to go manually update the assembly's File Version, and you don't find out about it until your users install the updated application and see no difference.

The method I posted before works fine, but it is a little complicated to setup and get going.

The new method I found is much easier to setup and use:

http://autobuildversion.codeplex.com/

Wednesday, May 25, 2011

What's new for Developers in Mango (and RIP .NET CF)

TechEd 2011 made me reminisce about my old frienemy the .NET Compact Framework. I will eulogize: Friends and fellow developers, we are here today to pay tribute to our friend of almost 10 years. We were coached, pushed, begged, and commanded to embrace you as you made life so much better for us. Yes, we had to be convinced of that, and we hated you at first. You could not go out without a healthy dose of p/invokes, work-arounds, and patches, but we managed to somehow embrace you as your capabilities grew. Now, you are gone. Plucked from us without notice.

I feel almost as sorry for CF as I did for myself after Microsoft threw its mobile developers under the bus last year when we were told there was no upgrade path from Windows Mobile to Windows Phone 7 (WP7). After stewing on this new direction last year, I have finally come to the conclusion that the abandonment of Window Mobile was actually a good thing. No, I have not embraced WP7. I had never seen another Windows Phone in the wild until I when to TechEd 2011 in Atlanta (and I have had my Samsung Focus since November 2010). Needless to say, the popularity of WP7 is so low it would be risky to venture off in that direction at this time. I am sure others feel the same way. One session at the conference said the ComScores for March 2011 placed Windows Mobile 6 together with WP7 at a 7.5% share of the smartphones in the US (and that is a total of 72.5 million smartphone users). Just for comparison, Android was 34.7%, RIM was 27.1%, and Apple was 25.5%. Since probably half of Microsoft’s 7.5% share is Windows Mobile, that leaves a paltry base of users to target (close to the Palm share of 2.8%). How many palm apps are people writing today? Now, you may ask why I think Microsoft’s throwing its mobile developers under the bus is a good thing. Well, it forced me to go develop for Android, BlackBerry, and iOS. I have traded my less than 7.5% Microsoft base for a 87.3% base. I may one day consider WP7 for my applications, but not today. The moral of the story for Microsoft is that if you tell your developers that they are going to have to rewrite their applications from scratch to run on the new version of the platform, they might spend those resources rewriting their apps for another platform (like Android). This business pattern is unfortunately pretty common (look at Intergraph’s upgrade from FRAMME to G/Technology).

Compiled from various sessions at TechEd, I will run down the list of the major new features Windows Phone will include for developers in its next released (called Mango):

  • Currently, the development platform is a subset of Silverlight 3 or a subset of XNA. The Silverlight 3 subset is being upgraded to a Silverlight 4 subset. There was also talk of blending Silverlight and XNA together to overcome problems in each. This blending will be at a page level (mixing Silverlight and XNA pages together in the same app) and at an element level (putting Silverlight elements on a XNA page, such as text). Regardless, it seems like a crazy mash up on many different levels.
  • From the Silverlight 4 upgrade, new features will include: implicit styles, data binding enhancements, and ICommand support.
  • New interfaces will be available for the camera. This feature should finally overcome one of my biggest complaints with WP7, my QR Code scanner app is pretty much useless when you have to take a picture instead of just “scanning”. Why wasn’t this in the first version?
  • A new Read-only Rich Text Box.
  • Clipboard API.
  • Tap, Double Tap, and Hold Events for Text Box.
  • Red Squiqqlies for misspelled words in a Text Box.
  • Support for Sockets which fills another big hole in the current version.
  • Video Brush so you can draw video on a page.
  • Live Tiles get a new API that allows them to be more accessible and provides new features like text on the Back of a Tile (these tiles flip over periodically to show what is on the back). Single apps can now have multiple tiles and the tiles can deep link to a specific page in the app. App can also control the pinning and unpinning of the tiles from the start page. Also, push notification can happen every 15 minutes instead of an hour, and there can now be 30 push notification endpoints instead of 15. There is supposed to be support for animation like the Xbox Live and People tiles too.
  • Push Notification Toast can Deep Link to pages in an app too.
  • There is supposed to be some multitasking and background processing too, but I wasn’t too clear on what this would be. Not having apps like Twitter or IM clients running in the background in the current version really kills the phone’s usefulness for most people.

Beyond the new features for Developers, Mango will also have the following enhancements:
  • Windows Phone 7 apps will run in a special mode to keep them compatible with the new version.
  • 32 BPP support for images, but defaults to 16 BPP. This feature can be used to fix banding problems with gradient shading (at the expense of performance).
  • Improved battery usage for Video Player which will now draw at ¾ size and scales up (with restrictions like must be right aligned)
  • Input thread introduced in ListBox to improve scrolling.
  • Improvements to memory management that will reduce memory usage in an app by 20 to 30%.
  • Off-thread Image decoding will allow ListBoxes with images to display and then fill in the images without hanging up.
  • Internet Explorer will be upgraded to IE9.
  • Rendering and Input for all languages will be supported.

Personally, I really like my Windows Phone as a phone. I find it unfortunate that it is too unpopular to invest any resources into developing apps for it. I think the Mango update will certainly help overcome its faults and maybe Nokia will eventually disseminate enough of these phones that their share of the market will be worthwhile. However, realigning development efforts to match the smartphone marketshare is unfortunately more urgent than waiting for Microsoft’s platform to come up to speed.

Tuesday, February 22, 2011

Center a Control on a Form in .NET

It turns out to be very easy to center a control on a .NET form. Just un-anchor the control from any side and it will center from its position. If you just un-anchor from the left and right it will center horizontally, and if you just un-anchor from the top and bottom, it will center vertically. Un-anchor from all sides and it will center on the form.

More info at:

http://stackoverflow.com/questions/491399/c-centering-controls-within-a-form-in-net-winforms

Friday, February 11, 2011

How solve the Problem of loading a Native DLL when using ASP.NET

I have had the problem of getting ASP.NET to use a Native DLL for years. I have even posted my complaints in a previous post. My quick and dirty solution has been to simply add the path that contains my DLL to the PATH environment variable and the process would find the .dlls that way. However, if you are using a hosted ASP.NET site or have clients that simply will NOT modify the PATH environment variable, the work around does not work. I have finally found the holy grail of information on how to solve this problem. Why I have not found it before I do not know, and I have search with Google for it a hundred times.

Here is the post I found:

http://blogs.msdn.com/b/jorman/archive/2007/08/31/loading-c-assemblies-in-asp-net.aspx


For ASP.NET, the solution is very simple and elegant. I copy it directly from Jerry Orman's excellent post:

In web.config, add the following…use a path where the Native C++ DLL is located:
<appsettings><add key="NativePath" value="C:\MyNativeDLLs"> </add>

In global.asax, add the following:

protected void Application_Start(object sender, EventArgs e){
String _path = String.Concat(System.Environment.GetEnvironmentVariable("PATH"), ";", ConfigurationSettings.AppSettings["NativePath"]);
System.Environment.SetEnvironmentVariable("PATH", _path, EnvironmentVariableTarget.Process);
}


This post also details other ways of solving the problem as well.