Thursday, October 22, 2009
The System.Drawing.Printing.PrintDocument class has the Print mode which will print your document directly to the printer. The Infragistics NetAdvantage suite has a couple of subclasses of PrintDocument. One of them is the Infragistics.Win.UltraWinGrid.UltraGridPrintDocument which is designed to print the contents of a specific data grid. The problem I ran into with the PrintDocument is that it prints to the default printer. There is no prompt for a different printer. However, as it turns out getting those details is very simple.
There are two ways to approach the problem. You can have the user specify the settings and then use those settings for every call you make until the settings are specifically changed, or you can prompt when a print request is made. I chose the latter, because it makes sense for my application and all you have to do is add a handler for the BeginPrint event of the PrintDocument.
private void ultraGridPrintDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
/* include this check otherwise the dialog will be
* displayed when a print preview is shown */
if (e.PrintAction == System.Drawing.Printing.PrintAction.PrintToPreview)
return;
using (PrintDialog dialog = new PrintDialog())
{
/* record the current printer settings for the document;
* otherwise, the default system settings are used */
dialog.PrinterSettings = ultraGridPrintDocument1.PrinterSettings;
if (dialog.ShowDialog(this) == DialogResult.OK)
ultraGridPrintDocument1.PrinterSettings = dialog.PrinterSettings;
else
e.Cancel = true;
}
}
The Infragistics NetAdvantage suite also has a preview dialog named Infragistics.Win.Printing.UltraPrintPreviewDialog. This class is similar to the one provided by the Framework, but it uses Infragistics controls and has a matching look-and-feel. The solution provided also works for using the print preview dialog. The one thing of note is that the print preview dialog allows the printer settings to be changed, but it's not direct (File --> Page Setup, click Printer, change settings, click OK). I ignore this possibility and display the dialog, because it's not something that will be an issue to my users.
Monday, September 14, 2009
Infragistics just released 2009 Volume 2 of their NetAdvantage Windows client controls which includes controls for Windows Forms and WPF.
New Controls:
- Timeline control
- Tile Panel
- WinControlContainerEditor
See the Infragistics New Features page for more information.
Friday, September 04, 2009
The UltraTimeline control is one of the new controls being released with this month's NetAdvantage for Windows Client release. The new UltraTimeline control is joined by a new layout metaphor called the UltraTilesPanel (see a video of both here). However, the timeline control is what I'm most excited about.
A timeline control displays a data series across a period of time for different subjects. For example, in a scheduling scenario a subject is a person and the data series is the appointments for each subject. The timeline has a large number of uses with scheduling and resource utilization being at the top of my concerns.
The following image is a sneek peek of the UltraTimeline control. You can also see it in use in the video linked above):

I've been using Infragistics controls for years now. Of all the suites I've used Infragistics has been my favorite. Besides the product itself one thing I like is that I know what to expect about upgrades. There is a consistent schedule and a consistent upgrade/support fee every year. This makes the accountants happy. And it makes me happy, because it's no hassle come upgrade time. Infragistics continues to provide additional value every year.
Thursday, August 06, 2009
I had the first bug that I reported resolved through Microsoft Connect today. The bug was minor and related to automatic comments in the Task List. The problem was that automatically generated tasks wouldn't get removed if you deleted a line of code that contained a token such as TODO or UNDONE.
I know it's pretty small, but I was proud nonetheless. The ID for the bug is 404851. The fix will be part of Visual Studio 2010.
Wednesday, July 22, 2009
I ran into an issue on Friday night while using the Infragistics controls within the scope of the Composite UI Application Block (CAB). My problem started when I tried to create a command with CAB from a UltraToolbarsManager tool using a function with a CommandHandler attribute that matched the signature of the event as shown below:
// statement within the work item
Commands["MyCommand"].AddInvoker(myTool, "ToolClick");
[CommandHandler("MyCommand")]
public void MyCommand(object sender, ToolClickEventArgs e)
{
// do something
}
The application compiles fine; however, at run-time you get an ArgumentException as soon as the class with the CommandHandler is added to the WorkItem. The message on the exception is "Error binding to target method." Internally, the CAB fails at CommandStrategy.CreateCommandHandler method.
After a little digging I determined that the EventArgs sub-classes such as ToolClickEventArgs are not serializable as is standard fare for EventArgs classes and that is apparently required by CAB. Typically in the case of a toolbar button click it will not matter, because all you care is what button was pushed. But, with the Infragistics UltraWinToolbars you can have different buttons such as a state button or a combo box button. In those cases you likely will need access to the state of the tool.
I opened up a support incident with Infragistics and this morning I was told that a feature request has been made. The feature request is FR11622 if you run into this same problem and want them to change it. At this point the request hasn't been committed to development, so please let them know if you need this too.
You can work-around this problem by changing the ToolClickEventArgs to EventArgs in your CommandHandler attributed method, but then you have to figure out a different way to get at the button state.
Monday, July 13, 2009
The databinding functionality for Windows Forms is pretty easy to use if not a little basic. However, the bindings do allow you to assign an IFormatProvider which would mean to me that you could format the data in any way you want. However, it appears that the formatting only applies for the purpose of globalization.
Instead, if you want custom formatting (ICustomFormatter) for your data you'll need to handle the Format event of the binding. You'll also have to handle the Parse event if your parseable data is not directly convertible to the underlying type and you want update functionality. Simply put the Format event allows you to tweak the value before it's displayed and the Parse event allows you to untweak the displayed value back to a value that the underlying type understands.
My example illustrates a simple binding using a formatter that pulls value from a resource file based on the default string representation of the object. In my case the object is a TraceLevel enumeration where I want to display "Error", "Warning", "Information", and "Debug" instead of "Error", "Warning", "Info", and "Verbose". I could have created a separate enumeration, but I still would have had the localization issue.
The data binding code is pretty simple:
Binding levelBinding = levelEditor.DataBindings.Add("Value", LogEntry,
"MessageLevel", true, DataSourceUpdateMode.Never, null, null,
MessageLevelFormatter.Instance);
levelBinding.Format += (sender, e) =>
e.Value = MessageLevelFormatter.Instance.Format(null, e.Value,
CultureInfo.CurrentCulture);
The ICustomFormatter and IFormatProvider code is also simple:
public class MessageLevelFormatter : IFormatProvider, ICustomFormatter
{
private static MessageLevelFormatter instance = new MessageLevelFormatter();
public static MessageLevelFormatter Instance
{
get
{
return instance;
}
}
public object GetFormat(Type formatType)
{
return (formatType == typeof(ICustomFormatter) ? this : null);
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (arg == null)
return null;
return Resources.ResourceManager.GetString(arg.ToString())
?? arg.ToString();
}
}
Monday, July 06, 2009
Tonight I ran into a problem running the start of a composite application that I was making work with the Infragistics support for the Composite UI application block. The problem occurred with the simplist implementation of an empty shell form. The exception was a configuration exception that said, "Configuration system failed to initialize" and it had an inner exception with the message, "Unrecognized configuration section userSettings..."
I let Visual Studio create a Settings class and add the configuration information to the App.Config (before this point I didn't have one), but the same problem occurred. Investigating the exception further I dug down into where it was pulling the configuration information. It was grabbing settings from within the user application data folder. In there was a configuration file that contained a toolbars layout file from a prototype that had a ToolbarsManager instance.
I deleted the file and rebuilt the project and it ran fine. Hopefully, this will help someone else out that gets a similar exception.
Friday, June 26, 2009
The other day Lindsay Rutter with Microsoft did a webcast on the Enterprise Library. I've used the exception handling block in a few projects, but my opinion had been that the library was bloated and was low on my priority list of technologies to investigate.
The talk on dependency injection in the webcast changed my mind. I immediately got a return on my investment as I wanted a more flexible method for tracing then what is offered from the Trace class in the System.Diagnostics namespace. And most importantly I didn't want any unnecessary dependencies in my library. Basically, my library wants the ability to log, but doesn't want any responsibility for it. Here's what I did:
- Added a reference to the Microsoft.Practices.Unity library. You'll need the Microsoft.Practices.ObjectBuilder2 library referenced wherever you create the unity container and inject the dependency. My library doesn't care about that. All it cares about is that whatever creates the key objects creates the dependencies.
- Define the interface for classes to perform the work. I created the ILoggingHandler with methods such as LogError, LogWarning, and LogInformation.
- Add a using statement for Microsoft.Practices.Unity to the code files containing your classes that you will be injecting.
- Add the following code to the classes that I want to log. There are undoubtedly other ways to approach this, but this is the most simple. At first I didn't think it was very elegant to add a property to my class, but these are base classes providing a service to subclasses, so I warmed up to the idea.
[Dependency]
public ILoggingHandler LogHandler { get; set; }
- Use the property within your code where necessary as in the following code.
LogHandler.LogInformation("Enter trace information here");
It's perfect for what I needed and is extremely simple to implement. When it comes to creating the logging service class I can create it and inject it from the code that hosts these classes using the following code (where DefaultLoggingHandler is my implementation of ILoggingHandler).
IUnityContainer container = new UnityContainer();
container.RegisterType<ILoggingHandler, DefaultLoggingHandler>(new ContainerControlledLifetimeManager());
MySubClass obj = container.Resolve<MySubClass>();
The optional parameter I specified in the call to RegisterType allows the object to be created as a Singleton. That means that every MySubClass object I create will use the same DefaultLoggingHandler.
I suggest that anyone who has discounted the Enterprise Library in the past take another look. I first used the Enterprise Library in one of it's first interations. It's grown and matured and can make some common, time consuming development activities go away.