|
Is there an equivalent to sprintf in C#? Basically I have some C# "value types" (floats, decimals) that I would like to format into a string variable. Also, I have a DateTime variable that I would like to format into a string variable. What is the best way to do this?
Thanks.
|
|
|
|
|
See String.Format in the .NET Framework SDK documentation. Many types - like the primitive types - implement IFormatProvider and have an overloaded ToString method which accepts the same format specifiers as you'd pass in String.Format :
double d = 1.5;
string a = string.Format("{0:C}", d);
string b = d.ToString("C");
Console.WriteLine(a == b); Other methods like StringBuilder.AppendFormat and Console.WriteLine can also accept format specifiers with parameter indexes.
For more information, also see my article, Custom String Formatting in .NET[^]. I also mention several reasons why String.Format and all the classes, methods, and interfaces that comprise formatting in .NET are better than any printf -like function.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Thanks Heath,
You beat me to my post below.
|
|
|
|
|
I think I got it. . . Its done by passing args to the ToString() method.
|
|
|
|
|
You still might want to look at what I wrote. Calling the overloaded ToString to format types isn't always the best way.
If you look at my article about custom format providers, you might notice why. When using String.Format (or similar methods), you can localize your application much easier because you can localize the entire format string and not have to worry about parameter order since you specify the parameter indexes in the format string. If all you're doing is printing a Type (like some primitive), then using ToString is fine. You should also keep in mind that the overridden ToString uses a well-defined output (typically the same as the "G" format specifier, although this is only a guidelines).
I also have several links in my article to more information in .NET Framework SDK. No, I'm not trying to market my article, I just don't feel like copying and pasting all the links. There's just a lot more power in string formatting within .NET and it's worth understanding.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Heath,
I just read your article; thanks for posting it. It brings together all the MSDN articles that I had read and the ones that I missed and it cuts straight to the point.
Thanks again.
|
|
|
|
|
If somebody could make sense of the behaviour of the following code, I'd be really happy.
On the second line, either #define CRASH to have it crash or don't to have it, well, not crash.
Then just pick the menu items sequentially from 1 to 4.
The only difference is that in the crashing version, a UserControl is added as a control to a Panel instead of directly to a Form...
After closing the form created in step 4, the application freezes, sometimes terminates with an ObjectDisposedException ...
Cheers,
Gunther
------------- CODE STARTS HERE -------------
// define "CRASH" to have it crash when you go from 1 to 4 ...
#define CRASH
using System;
namespace TestApp
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
[STAThread]
static void Main()
{
System.Windows.Forms.Application.Run(new Form1());
}
private System.Windows.Forms.Panel panel1;
public Form1()
{
this.panel1 = new System.Windows.Forms.Panel();
this.SuspendLayout();
//
// Menu
//
this.Menu = new System.Windows.Forms.MainMenu();
System.Windows.Forms.MenuItem mi = new System.Windows.Forms.MenuItem("Crashing!?");
this.Menu.MenuItems.Add(mi);
mi = new System.Windows.Forms.MenuItem("1. Create Control");
mi.Click += new EventHandler(this.Create_Click);
this.Menu.MenuItems[0].MenuItems.Add(mi);
mi = new System.Windows.Forms.MenuItem("2. Display Dialog");
mi.Click += new EventHandler(this.Dialog_Click);
this.Menu.MenuItems[0].MenuItems.Add(mi);
mi = new System.Windows.Forms.MenuItem("3. Destroy Control");
mi.Click += new EventHandler(this.Destroy_Click);
this.Menu.MenuItems[0].MenuItems.Add(mi);
mi = new System.Windows.Forms.MenuItem("4. Display Dialog");
mi.Click += new EventHandler(this.Dialog_Click);
this.Menu.MenuItems[0].MenuItems.Add(mi);
mi = new System.Windows.Forms.MenuItem("-");
this.Menu.MenuItems[0].MenuItems.Add(mi);
mi = new System.Windows.Forms.MenuItem("Quit");
mi.Click += new EventHandler(this.Quit_Click);
this.Menu.MenuItems[0].MenuItems.Add(mi);
//
// panel1
//
this.panel1.AutoScroll = true;
this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(464, 326);
this.panel1.TabIndex = 1;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(464, 326);
this.Controls.Add(this.panel1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
#if (CRASH)
#else
this.panel1.Hide();
#endif
}
private void Quit_Click(object sender, System.EventArgs e)
{
this.Close();
}
private void Destroy_Click(object sender, System.EventArgs e)
{
#if (CRASH)
for (int i = this.panel1.Controls.Count - 1; i >= 0; i--)
{
if (this.panel1.Controls[i].GetType() == typeof(System.Windows.Forms.UserControl))
this.panel1.Controls.RemoveAt(i);
}
#else
for (int i = this.Controls.Count - 1; i >= 0; i--)
{
if (this.Controls[i].GetType() == typeof(System.Windows.Forms.UserControl))
this.Controls.RemoveAt(i);
}
#endif
}
private void Create_Click(object sender, System.EventArgs e)
{
System.Windows.Forms.UserControl umc = new System.Windows.Forms.UserControl();
umc.Controls.Add(new System.Windows.Forms.TextBox());
#if (CRASH)
this.panel1.Controls.Add(umc);
#else
this.Controls.Add(umc);
#endif
}
private void Dialog_Click(object sender, System.EventArgs e)
{
// show dialog
System.Windows.Forms.Form d = new System.Windows.Forms.Form();
d.ShowDialog();
d.Dispose();
}
}
}
|
|
|
|
|
Reason, I cannot give, but fix I can:
Replace:
if (this.panel1.Controls[i].GetType() == typeof(System.Windows.Forms.UserControl))
this.Controls.RemoveAt(i);
With:
if (this.panel1.Controls[i].GetType() == typeof(System.Windows.Forms.UserControl))
{
this.panel1.Controls[i].Controls.Clear();
this.panel1.Controls.RemoveAt(i);
}
Ran into this a while back....
|
|
|
|
|
Thanks je,
your suggestions works.
However, meanwhile I also found that simply calling a Dispose() instead of the RemoveAt() also works.
I also realized that my original problem was twofold - the one from the posted source, the other, giving the DisposeException only occurs when a LinkLabel control was part of a GroupBox on a UserControl ...
Well, I just avoid having those in GroupBoxes for now ...
Regards,
Gunther
|
|
|
|
|
I while ago a link was posted in this forum to a site that contains details of the specification of all the DllImport attribute specifications in order to P/Invoke them correctly. Unfortunately I've not been able to find it. Does anyone have the link?
"You can have everything in life you want if you will just help enough other people get what they want." --Zig Ziglar
The Second EuroCPian Event will be in Brussels on the 4th of September
|
|
|
|
|
|
|
|
Many thanks for the link. It has been most useful... So useful in fact that I've added it to my signature so everyone will know about it!
"You can have everything in life you want if you will just help enough other people get what they want." --Zig Ziglar
The Second EuroCPian Event will be in Brussels on the 4th of September
Can't manage to P/Invoke that Win32 API in .NET? Why not do interop the wiki way!
|
|
|
|
|
Got a "crash" in the designer. I have a custom form that has almost no code in it and works fine, both in code and in the designer. I create a new inherited form from that custom form. The inherited form *immediately* (i.e. I make no changes from the code that is generated) shows the following error when I try to open it in the designer: "Object reference not set to an instance of an object".
Note that the inherited form and the base form are NOT in the same assembly, but the inherited form's assembly DOES reference the base form's assembly.
Also note that the code compiled just fine, and runs fine when I create an instance of the inherited form.
Any takers?
~Steve
|
|
|
|
|
Where the classes are (i.e., in what assembly) doesn't matter so long as the assemblies are resolvable by the project that use types in those assemblies. This could be your problem.
Design-time components should typically be installed into the GAC for this very reason. See How the Runtime Locates Assemblies[^] in the .NET Framework SDK for more information.
You should also consider debugging VS.NET. Yes, that's right. Open another instance of VS.NET and either attach to the former devenv.exe process or start a new one. Open your projects (works best with debug builds, of course) and try designing your components. It's fairly common to do so when extending the design-time capabilities of your components.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Heath, thanks for the reply. I'll give it a go. Is there anything I should know about installing things into the GAC? If my base form and inherited form are both changing frequently, should I just put a post-build event to install dll's into the GAC after each build? I'm guessing that after a while I'll end up with a ton of useless versions of my dll in the GAC that way. Should I make "uninstall previous" and "install current" post-build events?
Again, thanks for your help...
~Steve
|
|
|
|
|
For one, don't use automatic versioning (i.e., using an asterisk (*) in your AssemblyVersionAttribute ). Fix your version numbers using a versioning schema to your liking. Version numbers on .NET assemblies actually mean something unlike version numbers for Win32 executables. If a two Types differ only by version numbers, they are not the same Type.
If you're going to install into the GAC, you have to sign your assembly (which you should do anyway - there's never an excuse not to). Use sn.exe -k KeyFile.snk to generate a key pair named KeyFile.snk (or whatever you want to call it) and set the path in your AssemblyKeyFileAttribute , or install it into a CSP using sn.exe -k KeyPair.snk MyKeyPair and use that name ("MyKeyPair") in your AssemblyKeyNameAttribute . I recommend using the same key pair for all your assemblies, or at least all your assemblies for a particular product.
You don't need to uninstall these as the GAC allows for side-by-side versioning of assemblies. If these assemblies are changing often, however, I recommend that that you don't install into the GAC and make sure you set up a Project reference - not a simple assembly reference - in your multi-project solution so that Project B has a dependency on Project A - not Project A's assembly. This keeps versions and builds of assemblies in sync and you should not have the problems you're having (unless something else is causing it, of course).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Excellent! Thanks a bunch for all the info. I will definitely plan on doing all of this (probably won't use the GAC, but WILL strongly name my assemblies).
I have indeed solved the problem with the designer (problem in original post), but see that I have some work to do in configuring my projects/assemblies.
One last question... you mention setting my version with the AssemblyVersionAttribute . That is fine, but this project will have 20+ assemblies once it is complete. I don't want to have to go into each assembly and update the build number for every "internal" build (about once every 3 days) and for each release of the project. Is there a good way to make that happen dynamically? (ok, now that I think about it, I should probably search the site for an article...)
Anyway, thanks again! You've been a real help.
~Steve
|
|
|
|
|
You won't really find any articles on this.
I manage a project with over 60 assemblies (it's a massive N-tier application with several alternative tiers and utilities). Automatic versioning was a nightmare. I quickly threw that out and went with a simple approach.
The major and minor version numbers don't change very often at all. The build number (the third number) is the number of days since Jan. 1, 2000 (wrote a simple program to calculate that) for the milestone. The revision is incremented for any changes done between milestones that must be published into the test directories.
See, the assembly version is really most important when you deploy your assemblies. Since one alternative tier of our application uses touchless dpeloyment over the Internet, Fusion (part of the assembling binding in the .NET Framework) downloads and caches assemblies based on their version number into the Temporary Assembly Cache (also allows for side-by-side versioning). If you fixed a bug and re-released an assembly with the same version, it may not be downloaded to clients who got the first one. That's when changing the versions is most important. You really don't need to change it in between builds when just testing on your machine.
This also causes massive nightmares when you use late-binding, i.e. instantiating Types using .NET reflection (like Activator.CreateInstance ; building plug-in style applications or using the provider pattern). You can use publisher policies (specially named assemblies, roughly) and/or the assemblyBinding section of the .config file to redirect assembly versions.
you should read Redirecting Assembly Versions[^] in the .NET Framework SDK for more information if you're interested.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Hmmm, well you've definitely caught my attention. I've been developing C++ for some time now, but this is my first go at .NET. I'm quickly learning that I have a ton to learn.
Thanks for the lesson (and the link). I'll start doing my homework now
~Steve
|
|
|
|
|
I am currently developing an asp.net application that develops crystal reports using the push method. What I am wondering is if I can allow the user to specify sort options during runtime while they are viewing the report information in the .asxp page? For instance I have a report that displays three bits of information about a part(PartNumber,RevisionNumber,CallNumber). I am wondering if I can allow the user to switch between sorting the records by these given fields and just have the page reload with the same data in the newly selected sorted order. Thanks in advance for any help
Frank Lepkowski
PS Sorry if this is not posted where it should be I was not sure were to stick the post!
Live today like it's the last day of your life..........
|
|
|
|
|
Yes you can specify which fields to sort, and there is, IIRC, even an example in the CR for .NET (not C# .NET - any .NET language unless the CR assemblies aren't CLS-compliant, but that only rules out crappy languages like JScript.NET).
There are several ways you could do this. You could specify a grouping in your report that accepts parameters. There are several ways to pass those, which are documented in the CR documentation. For example, you could set parameters using the ReportDocument.DataDefinition property.
You could also design the report to use an ADO.NET DataSet , which would give you maximum flexibility since you could sort and filter the DataSet and then set that as the report data source using ReportDefinition.SetDataSource .
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
My reports have been reporting off of ADO.NET datasets the whole time, this will be perfect I can just sort the dataset before i set the report source!
Thanks Heath
|
|
|
|
|
How would I go about creating a Properties file for the Tab Control ?
|
|
|
|