Posts Tagged ‘C#’

WPF: Focus DatePicker on Text in TextBox

February 20th, 2011

I’ve been using the DatePicker control (which can be found in WPF 4.0 as well as the WPF Toolkit) and have come across a situation where I would like to set keyboard focus on a DatePicker programmatically so that the user can immediately begin typing a date into the control. Well like many other people out there I attempted to do this by calling the controls Focus() method and when that didn’t have the desired results I tried Keyboard.Focus() and passed it the DatePicker. This also didn’t accomplish what I was looking for.

In the above cases the DatePicker would indeed gain focus, however you could not immediately begin typing in a date. If you pressed a navigational key on the keyboard such as Tab or any of the directional arrows it would then put the keyboard focus into the TextBox portion of the control and highlight any existing text.

DatePicker without focus on text

Focus, but not on text...



DatePicker with focus on text

Focus on text!


Since this is exactly the end result I was after I set about automating this in code and arrived at the following solution. Basically all I’m doing is simulating the Up Arrow being pressed on the DatePicker control, this causes the control to move focus to the internal TextBox. It’s very hacky but it’s the best thing I could come up with without inheriting from DatePicker which I’d like to avoid. I wrapped the code up in a nice extension method for ease of use, and that’s what you see below.

using System.Windows.Controls;
using System.Windows.Input;
 
namespace CGS
{
    public static class DatePickerExtensions
    {
        public static void FocusOnText(this DatePicker datePicker)
        {
            Keyboard.Focus(datePicker);
 
            var eventArgs = new KeyEventArgs(Keyboard.PrimaryDevice,
                                             Keyboard.PrimaryDevice.ActiveSource,
                                             0,
                                             Key.Up);
            eventArgs.RoutedEvent = DatePicker.KeyDownEvent;
 
            datePicker.RaiseEvent(eventArgs);
        }
    }
}

If anyone knows of a cleaner, more legitimate way to accomplish this please let me know! As always questions and comments are welcome and appreciated.

C#: Refresh Windows Desktop and Explorer

September 2nd, 2010

This post is mostly for my own reference since the following code is actually found elsewhere online and is not my original work. However the code to both refresh the desktop and any open explorer windows is generally found in parts, so here I’ve combined it for convenience sake.

[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
 
public static void RefreshWindowsExplorer()
{
    // Refresh the desktop
    SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
 
    // Refresh any open explorer windows
    // based on http://stackoverflow.com/questions/2488727/refresh-windows-explorer-in-win7
    Guid CLSID_ShellApplication = new Guid("13709620-C279-11CE-A49E-444553540000");
    Type shellApplicationType = Type.GetTypeFromCLSID(CLSID_ShellApplication, true);
 
    object shellApplication = Activator.CreateInstance(shellApplicationType);
    object windows = shellApplicationType.InvokeMember("Windows", System.Reflection.BindingFlags.InvokeMethod, null, shellApplication, new object[] { });
 
    Type windowsType = windows.GetType();
    object count = windowsType.InvokeMember("Count", System.Reflection.BindingFlags.GetProperty, null, windows, null);
    for (int i = 0; i < (int)count; i++)
    {
        object item = windowsType.InvokeMember("Item", System.Reflection.BindingFlags.InvokeMethod, null, windows, new object[] { i });
        Type itemType = item.GetType();
 
        // Only refresh Windows Explorer, without checking for the name this could refresh open IE windows
        string itemName = (string)itemType.InvokeMember("Name", System.Reflection.BindingFlags.GetProperty, null, item, null);
        if (itemName == "Windows Explorer")
        {
            itemType.InvokeMember("Refresh", System.Reflection.BindingFlags.InvokeMethod, null, item, null);
        }
    }
}

OfficeToXps: Convert Word, Excel, and PowerPoint to XPS

May 11th, 2010

I recently had the need to convert Word, Excel, and PowerPoint files to Microsoft’s XPS format for easy displaying in WPF. There’s a plethora of articles, threads, and questions out there that illustrate how to do this, but I haven’t seen anyone compile a single class/library that will convert from all three applications with good error handling and no price tag.

So I figured since I had to write it anyway I’d post it here for the aid of anyone else looking to do the same thing. As always comments/questions/praise are appreciated.

Download Code File

using System;
using System.Collections.Generic;
using System.IO;
using Excel = Microsoft.Office.Interop.Excel;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using Word = Microsoft.Office.Interop.Word;
 
namespace CGS
{
    public class OfficeToXps
    {
        #region Properties & Constants
        private static List<string> wordExtensions = new List<string>
        {
            ".doc",
            ".docx"
        };
 
        private static List<string> excelExtensions = new List<string>
        {
            ".xls",
            ".xlsx"
        };
 
        private static List<string> powerpointExtensions = new List<string>
        {
            ".ppt",
            ".pptx"
        };
 
        #endregion
 
        #region Public Methods
        public static OfficeToXpsConversionResult ConvertToXps(string sourceFilePath, ref string resultFilePath)
        {
            var result = new OfficeToXpsConversionResult(ConversionResult.UnexpectedError);
 
            // Check to see if it's a valid file
            if (!IsValidFilePath(sourceFilePath))
            {
                result.Result = ConversionResult.InvalidFilePath;
                result.ResultText = sourceFilePath;
                return result;
            }
 
 
 
            var ext = Path.GetExtension(sourceFilePath).ToLower();
 
            // Check to see if it's in our list of convertable extensions
            if (!IsConvertableFilePath(sourceFilePath))
            {
                result.Result = ConversionResult.InvalidFileExtension;
                result.ResultText = ext;
                return result;
            }
 
            // Convert if Word
            if (wordExtensions.Contains(ext))
            {
                return ConvertFromWord(sourceFilePath, ref resultFilePath);
            }
 
            // Convert if Excel
            if (excelExtensions.Contains(ext))
            {
                return ConvertFromExcel(sourceFilePath, ref resultFilePath);
            }
 
            // Convert if PowerPoint
            if (powerpointExtensions.Contains(ext))
            {
                return ConvertFromPowerPoint(sourceFilePath, ref resultFilePath);
            }
 
            return result;
        }
        #endregion
 
        #region Private Methods
        public static bool IsValidFilePath(string sourceFilePath)
        {
            if (string.IsNullOrEmpty(sourceFilePath))
                return false;
 
            try
            {
                return File.Exists(sourceFilePath);
            }
            catch (Exception)
            {
            }
 
            return false;
        }
 
        public static bool IsConvertableFilePath(string sourceFilePath)
        {
            var ext = Path.GetExtension(sourceFilePath).ToLower();
 
            return IsConvertableExtension(ext);
        }
        public static bool IsConvertableExtension(string extension)
        {
            return wordExtensions.Contains(extension) ||
                   excelExtensions.Contains(extension) ||
                   powerpointExtensions.Contains(extension);
        }
 
        private static string GetTempXpsFilePath()
        {
            return Path.ChangeExtension(Path.GetTempFileName(), ".xps");
        }
 
 
        private static OfficeToXpsConversionResult ConvertFromWord(string sourceFilePath, ref string resultFilePath)
        {
            object pSourceDocPath = sourceFilePath;
 
            string pExportFilePath = string.IsNullOrWhiteSpace(resultFilePath) ? GetTempXpsFilePath() : resultFilePath;
 
            try
            {
                var pExportFormat = Word.WdExportFormat.wdExportFormatXPS;
                bool pOpenAfterExport = false;
                var pExportOptimizeFor = Word.WdExportOptimizeFor.wdExportOptimizeForOnScreen;
                var pExportRange = Word.WdExportRange.wdExportAllDocument;
                int pStartPage = 0;
                int pEndPage = 0;
                var pExportItem = Word.WdExportItem.wdExportDocumentContent;
                var pIncludeDocProps = true;
                var pKeepIRM = true;
                var pCreateBookmarks = Word.WdExportCreateBookmarks.wdExportCreateWordBookmarks;
                var pDocStructureTags = true;
                var pBitmapMissingFonts = true;
                var pUseISO19005_1 = false;
 
 
                Word.Application wordApplication = null;
                Word.Document wordDocument = null;
 
                try
                {
                    wordApplication = new Word.Application();
                }
                catch (Exception exc)
                {
                    return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToInitializeOfficeApp, "Word", exc);
                }
 
                try
                {
                    try
                    {
                        wordDocument = wordApplication.Documents.Open(ref pSourceDocPath);
                    }
                    catch (Exception exc)
                    {
                        return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToOpenOfficeFile, exc.Message, exc);
                    }
 
                    if (wordDocument != null)
                    {
                        try
                        {
                            wordDocument.ExportAsFixedFormat(
                                                pExportFilePath,
                                                pExportFormat,
                                                pOpenAfterExport,
                                                pExportOptimizeFor,
                                                pExportRange,
                                                pStartPage,
                                                pEndPage,
                                                pExportItem,
                                                pIncludeDocProps,
                                                pKeepIRM,
                                                pCreateBookmarks,
                                                pDocStructureTags,
                                                pBitmapMissingFonts,
                                                pUseISO19005_1
                                            );
                        }
                        catch (Exception exc)
                        {
                            return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToExportToXps, "Word", exc);
                        }
                    }
                    else
                    {
                        return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToOpenOfficeFile);
                    }
                }
                finally
                {
                    // Close and release the Document object.
                    if (wordDocument != null)
                    {
                        wordDocument.Close();
                        wordDocument = null;
                    }
 
                    // Quit Word and release the ApplicationClass object.
                    if (wordApplication != null)
                    {
                        wordApplication.Quit();
                        wordApplication = null;
                    }
 
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
            }
            catch (Exception exc)
            {
                return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToAccessOfficeInterop, "Word", exc);
            }
 
            resultFilePath = pExportFilePath;
 
            return new OfficeToXpsConversionResult(ConversionResult.OK, pExportFilePath);
        }
 
        private static OfficeToXpsConversionResult ConvertFromPowerPoint(string sourceFilePath, ref string resultFilePath)
        {
            string pSourceDocPath = sourceFilePath;
 
            string pExportFilePath = string.IsNullOrWhiteSpace(resultFilePath) ? GetTempXpsFilePath() : resultFilePath;
 
            try
            {
                PowerPoint.Application pptApplication = null;
                PowerPoint.Presentation pptPresentation = null;
 
                try
                {
                    pptApplication = new PowerPoint.Application();
                }
                catch (Exception exc)
                {
                    return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToInitializeOfficeApp, "PowerPoint", exc);
                }
 
                try
                {
                    try
                    {
                        pptPresentation = pptApplication.Presentations.Open(pSourceDocPath,
                                                                            Microsoft.Office.Core.MsoTriState.msoTrue,
                                                                            Microsoft.Office.Core.MsoTriState.msoTrue,
                                                                            Microsoft.Office.Core.MsoTriState.msoFalse);
                    }
                    catch (Exception exc)
                    {
                        return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToOpenOfficeFile, exc.Message, exc);
                    }
 
                    if (pptPresentation != null)
                    {
                        try
                        {
                            pptPresentation.ExportAsFixedFormat(
                                                pExportFilePath,
                                                PowerPoint.PpFixedFormatType.ppFixedFormatTypeXPS,
                                                PowerPoint.PpFixedFormatIntent.ppFixedFormatIntentScreen,
                                                Microsoft.Office.Core.MsoTriState.msoFalse,
                                                PowerPoint.PpPrintHandoutOrder.ppPrintHandoutVerticalFirst,
                                                PowerPoint.PpPrintOutputType.ppPrintOutputSlides,
                                                Microsoft.Office.Core.MsoTriState.msoFalse,
                                                null,
                                                PowerPoint.PpPrintRangeType.ppPrintAll,
                                                string.Empty,
                                                true,
                                                true,
                                                true,
                                                true,
                                                false
                                            );
                        }
                        catch (Exception exc)
                        {
                            return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToExportToXps, "PowerPoint", exc);
                        }
                    }
                    else
                    {
                        return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToOpenOfficeFile);
                    }
                }
                finally
                {
                    // Close and release the Document object.
                    if (pptPresentation != null)
                    {
                        pptPresentation.Close();
                        pptPresentation = null;
                    }
 
                    // Quit Word and release the ApplicationClass object.
                    if (pptApplication != null)
                    {
                        pptApplication.Quit();
                        pptApplication = null;
                    }
 
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
            }
            catch (Exception exc)
            {
                return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToAccessOfficeInterop, "PowerPoint", exc);
            }
 
            resultFilePath = pExportFilePath;
 
            return new OfficeToXpsConversionResult(ConversionResult.OK, pExportFilePath);
        }
 
        private static OfficeToXpsConversionResult ConvertFromExcel(string sourceFilePath, ref string resultFilePath)
        {
            string pSourceDocPath = sourceFilePath;
 
            string pExportFilePath = string.IsNullOrWhiteSpace(resultFilePath) ? GetTempXpsFilePath() : resultFilePath;
 
            try
            {
                var pExportFormat = Excel.XlFixedFormatType.xlTypeXPS;
                var pExportQuality = Excel.XlFixedFormatQuality.xlQualityStandard;
                var pOpenAfterPublish = false;
                var pIncludeDocProps = true;
                var pIgnorePrintAreas = true;
 
 
                Excel.Application excelApplication = null;
                Excel.Workbook excelWorkbook = null;
 
                try
                {
                    excelApplication = new Excel.Application();
                }
                catch (Exception exc)
                {
                    return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToInitializeOfficeApp, "Excel", exc);
                }
 
                try
                {
                    try
                    {
                        excelWorkbook = excelApplication.Workbooks.Open(pSourceDocPath);
                    }
                    catch (Exception exc)
                    {
                        return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToOpenOfficeFile, exc.Message, exc);
                    }
 
                    if (excelWorkbook != null)
                    {
                        try
                        {
                            excelWorkbook.ExportAsFixedFormat(
                                                pExportFormat,
                                                pExportFilePath,
                                                pExportQuality,
                                                pIncludeDocProps,
                                                pIgnorePrintAreas,
 
                                                OpenAfterPublish : pOpenAfterPublish
                                            );
                        }
                        catch (Exception exc)
                        {
                            return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToExportToXps, "Excel", exc);
                        }
                    }
                    else
                    {
                        return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToOpenOfficeFile);
                    }
                }
                finally
                {
                    // Close and release the Document object.
                    if (excelWorkbook != null)
                    {
                        excelWorkbook.Close();
                        excelWorkbook = null;
                    }
 
                    // Quit Word and release the ApplicationClass object.
                    if (excelApplication != null)
                    {
                        excelApplication.Quit();
                        excelApplication = null;
                    }
 
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
            }
            catch (Exception exc)
            {
                return new OfficeToXpsConversionResult(ConversionResult.ErrorUnableToAccessOfficeInterop, "Excel", exc);
            }
 
            resultFilePath = pExportFilePath;
 
            return new OfficeToXpsConversionResult(ConversionResult.OK, pExportFilePath);
        }
        #endregion
    }
 
    public class OfficeToXpsConversionResult
    {
        #region Properties
        public ConversionResult Result { get; set; }
        public string ResultText { get; set; }
        public Exception ResultError { get; set; } 
        #endregion
 
        #region Constructors
        public OfficeToXpsConversionResult()
        {
            Result = ConversionResult.UnexpectedError;
            ResultText = string.Empty;
        }
        public OfficeToXpsConversionResult(ConversionResult result)
            : this()
        {
            Result = result;
        }
        public OfficeToXpsConversionResult(ConversionResult result, string resultText)
            : this(result)
        {
            ResultText = resultText;
        }
        public OfficeToXpsConversionResult(ConversionResult result, string resultText, Exception exc)
            : this(result, resultText)
        {
            ResultError = exc;
        } 
        #endregion
    }
 
    public enum ConversionResult
    {
        OK = 0,
        InvalidFilePath = 1,
        InvalidFileExtension = 2,
        UnexpectedError = 3,
        ErrorUnableToInitializeOfficeApp = 4,
        ErrorUnableToOpenOfficeFile = 5,
        ErrorUnableToAccessOfficeInterop = 6,
        ErrorUnableToExportToXps = 7
    }
}

This solution uses the 2007 Office Interop libraries for Word, Excel, and PowerPoint. To compile it in Visual Studio you’ll need to reference these assemblies in your project. For example here’s what the Word assembly looks like:

Also note that I’ve made use of some shortcuts provided by the new optional parameters in C# 4.0. If you’re using an earlier version of .Net you’ll have to make some changes to the interop calls, but it’s nothing serious.

Here’s a quick example of using the given code in an application:

string filePath = @"C:\Test\Test.doc";
string xpsFilePath = @"C:\Test\Test.xps";
 
var convertResults = OfficeToXps.ConvertToXps(filePath, ref xpsFilePath);
 
switch (convertResults.Result)
{
    case ConversionResult.OK:
        XpsDocument xpsDoc = new XpsDocument(xpsFilePath, FileAccess.ReadWrite);
        break;
 
    case ConversionResult.InvalidFilePath:
        // Handle bad file path or file missing
        break;
    case ConversionResult.UnexpectedError:
        // This should only happen if the code is modified poorly
        break;
    case ConversionResult.ErrorUnableToInitializeOfficeApp:
        // Handle Office 2007 (Word | Excel | PowerPoint) not installed
        break;
    case ConversionResult.ErrorUnableToOpenOfficeFile:
        // Handle source file being locked or invalid permissions
        break;
    case ConversionResult.ErrorUnableToAccessOfficeInterop:
        // Handle Office 2007 (Word | Excel | PowerPoint) not installed
        break;
    case ConversionResult.ErrorUnableToExportToXps:
        // Handle Microsoft Save As PDF or XPS Add-In missing for 2007
        break;
}

ProgressStream: A Stream with Read and Write events

January 19th, 2010

In my experience with WCF I’ve implemented several solutions that leverage the message streaming capabilities present in the framework. Specifically in a client/server scenario when either side needs to transfer a file to the other side it is really convenient to be able to just pass a FileStream to a WCF service call and have the server read bytes from it and write them to disk as it pleases.

However, in this exact scenario, while the server can monitor and control how the bytes are read from the stream and track the progress, the client has no inherent way of determining how much of the file has been read across the network by the server. It would be really useful if the client could track this upload progress and display a progress bar or percentage to the user.

Well, I’ve created one of probably many possible solutions to this dilemma. I’ve written a class that inherits from Stream and exposes some events that are raised when bytes are read or written to/from the stream. These events provide information for how many bytes were read from the stream, what the current position is in the stream, and what the stream’s total length is.

The ProgressStream, as I call it, accepts any Stream object and encapsulates it, forwarding all regular stream calls to the underlying object. With this you can use the ProgressStream in conjunction with any other stream in .Net and leverage the added functionality.

Well enough explanation, here’s the code:

ProgressStream.cs (C#)
ProgressStream.vb (VB.Net)

And here’s a simple example in C# of how to use it:

using System;
using System.IO;
using CGS;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var test = File.OpenRead(@"C:\Test\Test.doc");
 
            var pStream = new ProgressStream(test);
            pStream.BytesRead += 
                new ProgressStreamReportDelegate(pStream_BytesRead);
 
            int bSize = 4320;
            byte[] buffer = new byte[bSize];
            while (pStream.Read(buffer, 0, bSize) > 0) { }
 
            Console.ReadKey();
        }
 
        static void pStream_BytesRead(object sender, 
                                      ProgressStreamReportEventArgs args)
        {
            Console.WriteLine(
                string.Format("{2} bytes moved | {0} of {1} total", 
                    args.StreamPosition, 
                    args.StreamLength, 
                    args.BytesMoved
                )
           );
        }
    }
}

WPF: Simple Vista Image Viewer

September 25th, 2009

Preview of WPF Image Viewer

Download source code – 72.2 KB
Download sample app – 67.8 KB

What does it do?

This lightweight WPF UserControl will display a single image in a manner similar to the Windows Photo Gallery. It doesn’t manage more than one image in a gallery or slideshow fashion however, but it does:

  • Zoom In/Out both with the mouse and with a slider control
  • Pan the image with the mouse
  • Rotate the image clockwise or counter-clockwise 90 degrees
  • Keep the image fully visible in the display area when not in zoom mode

How can I use it?

You can use this image viewer in any WPF application with little effort since it’s built as a WPF UserControl. By leveraging the WPF Interoperability in WinForms it’s possible to use this in a Windows Forms application as well, see the article here for instructions on accomplishing that.

To get started using the control, download the source project from the above link. You can play around with the sample application to see an example of how to use the image viewer. The sample program simply provides a Window for the control and sets the path for the image to display; the control does all the rest.

To use the control in your own application you simply need to include the necessary source files in your own project or solution (CgsImageViewer.xaml(.cs), PanAndZoom.cs, and the images for the buttons). Once you’ve got them, you’ll begin by inserting the viewer into your XAML, like so:

<Window x:Class="ImageViewer.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:iv="clr-namespace:ImageViewer"
    Title="Image Viewer Sample" Height="418" Width="410">
    <Grid>
        <iv:CgsImageViewer x:Name="cgsImageViewer" />
    </Grid>
</Window>

This is just placing the image viewer in a window and giving it a name. Now to load up an image all that you need to do is provide a path to the image or a BitmapImage object. You can do this in the business code or in the XAML by means of a data binding. Here’s an example of setting the image in the business code:

cgsImageViewer.CurrentImagePath = @"c:\test images\cat-plans-your-doom.jpg";

That’s all you really need to know to use the image viewer. Continue on for some extra info.

Class Members you might want to know about:

  •  CurrentImage – Gets or sets the current BitmapImage used by the viewer.
  •  CurrentImagePath – Gets or sets a string representing the Uri to load an image from.
  •  ZoomLevel – Gets or sets a double representing the percentage to zoom.
  •  ScaleToFit – Resizes the image to fit within the visible bounds.
  •  RotateLeft – Rotates the image 90 degrees to the left and scales it to fit.
  •  RotateRight – Rotates the image 90 degrees to the right and scales it to fit.

(Note: The code for panning and zooming was found here)

A little background and explanation:

I wrote this control in a grand total of about two days, which included testing. It was written for use in a WPF project I’m currently working on where users needed to be able to preview graphic files inside the program. I decided to make something that could be re-used and would provide simple viewing capabilities.

So here you go. If you’ve used it and like it why not leave a comment or trackback. If you find any bugs or have some ideas to improve on it let me know. I’m always looking to make things better!