Archive

Archive for the ‘.Net’ Category

Customize SpellCheck in WPF textbox

June 22nd, 2010 Anuraj P No comments

While working on a personal project (fleetIt). I worked on Textbox spell check option. I enabled it, it was working fine, until I added a context menu to to the textbox, for custom commands of my application. It was displaying the spelling errors but the suggestions and correction options was not available. Then I tried to customize the context menu such a way that it can display both my custom options as well as the system default spell check options. Here is a simple implementation, which helps to customize the context menu and display the spell check suggestions options.

<Window x:Class="dotnetthoughts.net.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=System"
Title="WPF SpellCheck Demo" Height="350" Width="525" Loaded="Window_Loaded">
<DockPanel>
<TextBox Name="txtEdit" SpellCheck.IsEnabled="True"
                AcceptsReturn="True"
ContextMenuOpening="txtEdit_ContextMenuOpening"
                VerticalScrollBarVisibility="Visible">
<TextBox.ContextMenu>
<ContextMenu Name="ctxMenu" />
</TextBox.ContextMenu>
</TextBox>
</DockPanel>
</Window>

And here is the code behind

namespace dotnetthoughts.net
{
    using System;
    using System.IO;
using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;

public partial class MainWindow : Window
    {
public MainWindow()
        {
InitializeComponent();
        }

private void txtEdit_ContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            int index = 0;
this.txtEdit.ContextMenu.Items.Clear(); //Clearing the existing items
            //Getting the spellcheck suggestions.
SpellingError spellingError = this.txtEdit.GetSpellingError(this.txtEdit.CaretIndex);
if (spellingError != null && spellingError.Suggestions.Count() >= 1)
            {
                //Creating the suggestions menu items.
foreach (string suggestion in spellingError.Suggestions)
                {
MenuItem menuItem = new MenuItem();
                    menuItem.Header = suggestion;
menuItem.FontWeight = FontWeights.Bold;
menuItem.Command = EditingCommands.CorrectSpellingError;
                    menuItem.CommandParameter = suggestion;
menuItem.CommandTarget = this.txtEdit;
this.txtEdit.ContextMenu.Items.Insert(index, menuItem);
                    index++;
                }
Separator seperator = new Separator();
this.txtEdit.ContextMenu.Items.Insert(index, seperator);
                index++;
//Adding the IgnoreAll menu item
MenuItem IgnoreAllMenuItem = new MenuItem();
                IgnoreAllMenuItem.Header = "Ignore All";
IgnoreAllMenuItem.Command = EditingCommands.IgnoreSpellingError;
IgnoreAllMenuItem.CommandTarget = this.txtEdit;
                this.txtEdit.ContextMenu.Items.Insert(index, IgnoreAllMenuItem);
                index++;
            }
            else
            {
//No Suggestions found, add a disabled NoSuggestions menuitem.
                MenuItem menuItem = new MenuItem();
menuItem.Header = "No Suggestions";
                menuItem.IsEnabled = false;
this.txtEdit.ContextMenu.Items.Insert(index, menuItem);
                index++;
            }
//.Net 4.0 Supports CustomDictionaries, Option for Adding to dictionary.
int selectionStart = this.txtEdit.GetSpellingErrorStart(this.txtEdit.CaretIndex);
            if (selectionStart >= 0)
            {
                Separator seperator1 = new Separator();
this.txtEdit.ContextMenu.Items.Insert(index, seperator1);
                index++;
MenuItem AddToDictionary = new MenuItem();
                AddToDictionary.Header = "Add to Dictionary";
                //Getting the word to add
this.txtEdit.SelectionStart = selectionStart;
this.txtEdit.SelectionLength = this.txtEdit.GetSpellingErrorLength(this.txtEdit.CaretIndex);
                //Ignoring the added word.
AddToDictionary.Command = EditingCommands.IgnoreSpellingError;
AddToDictionary.CommandTarget = this.txtEdit;
AddToDictionary.Click += (object o, RoutedEventArgs rea) =>
                {
this.AddToDictionary(this.txtEdit.SelectedText);
                };
this.txtEdit.ContextMenu.Items.Insert(index, AddToDictionary);
                index++;
            }

//Common Edit MenuItems.
            Separator seperator2 = new Separator();
this.txtEdit.ContextMenu.Items.Insert(index, seperator2);
            index++;
            //Cut
MenuItem cutMenuItem = new MenuItem();
cutMenuItem.Command = ApplicationCommands.Cut;
this.txtEdit.ContextMenu.Items.Insert(index, cutMenuItem);
            index++;
            //Copy
MenuItem copyMenuItem = new MenuItem();
copyMenuItem.Command = ApplicationCommands.Copy;
this.txtEdit.ContextMenu.Items.Insert(index, copyMenuItem);
            index++;
            //Paste
MenuItem pasteMenuItem = new MenuItem();
pasteMenuItem.Command = ApplicationCommands.Paste;
this.txtEdit.ContextMenu.Items.Insert(index, pasteMenuItem);
            index++;
            Separator seperator3 = new Separator();
this.txtEdit.ContextMenu.Items.Insert(index, seperator3);
            index++;
            //Delete
MenuItem deleteMenuItem = new MenuItem();
deleteMenuItem.Command = ApplicationCommands.Delete;
            this.txtEdit.ContextMenu.Items.Insert(index, deleteMenuItem);
            index++;
            Separator seperator4 = new Separator();
this.txtEdit.ContextMenu.Items.Insert(index, seperator4);
            index++;
            //Select All
MenuItem selectAllMenuItem = new MenuItem();
selectAllMenuItem.Command = ApplicationCommands.SelectAll;
            this.txtEdit.ContextMenu.Items.Insert(index, selectAllMenuItem);
            index++;
        }
        //Method to Add text to Dictionary
private void AddToDictionary(string entry)
        {
using (StreamWriter streamWriter = new StreamWriter(@"D:\WPF\MyCustomDictionary.lex", true))
            {
streamWriter.WriteLine(entry);
            }
        }

private void Window_Loaded(object sender, RoutedEventArgs e)
        {
//Assigning custom Dictionary to TextBox
this.txtEdit.SpellCheck.CustomDictionaries.Add(new Uri(@"D:\WPF\MyCustomDictionary.lex"));
        }
    }
}

The .Net Framework 4.0 supports CustomDictionaries, which helps to create your own Dictionary.

//.Net 4.0 Supports CustomDictionaries, Option for Adding to dictionary.
int selectionStart = this.txtEdit.GetSpellingErrorStart(this.txtEdit.CaretIndex);
if (selectionStart >= 0)
{
    Separator seperator1 = new Separator();
this.txtEdit.ContextMenu.Items.Insert(index, seperator1);
    index++;
MenuItem AddToDictionary = new MenuItem();
    AddToDictionary.Header = "Add to Dictionary";
    //Getting the word to add
this.txtEdit.SelectionStart = selectionStart;
this.txtEdit.SelectionLength = this.txtEdit.GetSpellingErrorLength(this.txtEdit.CaretIndex);
    //Ignoring the added word.
AddToDictionary.Command = EditingCommands.IgnoreSpellingError;
AddToDictionary.CommandTarget = this.txtEdit;
AddToDictionary.Click += (object o, RoutedEventArgs rea) =>
    {
this.AddToDictionary(this.txtEdit.SelectedText);
    };
this.txtEdit.ContextMenu.Items.Insert(index, AddToDictionary);
    index++;
}

Here is the screenshot of Demo Application.

WPF Spell Check Demo - Screenshot

WPF Spell Check Demo - Screenshot

Categories: .Net, .Net 3.0 / 3.5, WPF Tags: , , , ,

Custom Places in FileDialog box

June 21st, 2010 Anuraj P No comments

If you ever tried to Open a File from Visual Studio, you may notice something like Projects Folder in the Open File Dialog.

Open File Dialog in Visual Studio

Open File Dialog in Visual Studio

We can also implement the same functionality in our applications by using CustomPlaces collection property of FileDialog class. The OpenFileDialog and SaveFileDialog classes allow you to add folders to the CustomPlaces collection.

openFileDialog.CustomPlaces.Add(@"C:\Users");

You can also specify GUID of Windows Vista known folder. Known Folder GUIDs are not case sensitive and are defined in the KnownFolders.h file in the Windows SDK. If the specified Known Folder is not present on the computer that is running the application, the Known Folder is not shown.

openFileDialog.CustomPlaces.Add(@"C:\Users");
//Desktop Folder
openFileDialog.CustomPlaces.Add(new Guid("B4BFCC3A-DB2C-424C-B029-7FE99A87C641"));
//Downloads Folder
openFileDialog.CustomPlaces.Add(new Guid("374DE290-123F-4565-9164-39C4925E467B"));
Open File Dialog with Custom Places

Open File Dialog with Custom Places

Note: This feature will not have any effect in Windows XP. Also you must set the AutoUpgradeEnabled to True(default) to enable this feature in Vista or Windows 7.

The following table lists few Windows Vista Known Folders and their associated Guid.

  1. Contacts : 56784854-C6CB-462B-8169-88E350ACB882
  2. ControlPanel : 82A74AEB-AEB4-465C-A014-D097EE346D63
  3. Desktop : B4BFCC3A-DB2C-424C-B029-7FE99A87C641
  4. Documents : FDD39AD0-238F-46AF-ADB4-6C85480369C7
  5. Downloads : 374DE290-123F-4565-9164-39C4925E467B
  6. Favorites : 1777F761-68AD-4D8A-87BD-30B759FA33DD
  7. Fonts : FD228CB7-AE11-4AE3-864C-16F3910AB8FE
  8. Music : 4BD8D571-6D19-48D3-BE97-422220080E43

ASP.Net Default button and Master Pages

June 21st, 2010 Anuraj P 3 comments

Last few days I was(am) busy with one pure ASP.Net application(why its pure because we are not using any 3rd party controls, ajax nothing. Everything is postbacking ;) ). Today I got a weird bug from one of my QC team saying when ever they presses ENTER button, focus is on any textbox, it popups Help window from our application. In our application, end users can open the Help window, by clicking on some help images icons provided in the application. These images are displayed using ASP Image button controls (If you are using ASP Image controls this problem will not occur, but in our application, we need to disable it some scenarios, so can’t use ASP Image). After searching I found the issue with the default button property of ASP.Net, which helps us to submit the form using Enter Key. In my page ASP.Net considering the Help image button as default button for the Page. We can set the default button to our submit button using various methods. Set the default button property of the FORM, or create a Panel control over the controls and set the default button property of the Panel.

<form id="form1" runat="server" defaultbutton="cmdSubmit">
<asp:Panel runat="server" ID="plMain" DefaultButton="cmdSubmit">

Form tag also supports “defaultfocus” this property allows to focus to control, on Page Load.

<form id="form1" runat="server" defaultbutton="cmdSubmit" defaultfocus="txtUser">

If you are using Master Pages, there will be some slight difference because, the Form tag will not be available in the content Pages. It can fix using code behind, using FindControl method.

(Page.Master.FindControl("Form1") as HtmlForm).DefaultButton = this.cmdSubmit.UniqueID;

Also you can do something like this

Page.Master.Page.Form.DefaultButton = cmdSubmit.UniqueID;

Happy Coding :)

Pass your own arguments to the ClientValidationFunction in a CustomValidator

May 30th, 2010 Anuraj P No comments

Last few days I am working on an ASP.Net, where I can create Grids, Dropdown lists with Post back :) , and the best part is browser compatibility, client only requires compatible with IE. Yes it was a refresher course for me, I revisited GridView templates, Page.IsPostback checking etc. Today I got a requirement like I need to validate few radio buttons. I searched for an implementation, I found we can use required field validator for RadioButtonList, but in my case it was Radio buttons (Initially it was RadioButtonList, but due to some customization issues, I changed it to Radio Buttons). Then I implemented a custom validator, and in the client validation function I hardcoded the Radio Button ids, because for the client validation function we can’t pass the parameters to the function. Same problem again I faced in a GridView, where the problem I found was I won’t get the client id of the radio button in the Item template. :( After doing some research I found we can extend the custom validator control using Validation Framework. And here is the implementation. Using this we can add properties to the source / sender parameter in the client side validation function.

function ValidateRadioButtons(source, arguments) {
    var radio1 = document.getElementById(source.Radio1);
    var radio2 = document.getElementById(source.Radio2);
    var radio4 = document.getElementById(source.Radio4);
    var radio3 = document.getElementById(source.Radio3);
    var result = radio1.checked || radio2.checked || radio3.checked || radio4.checked;
    arguments.IsValid = result;
}

This is the JavaScript function which implements the validation logic. You can get the controls as part of the Source object. To get the Source.Radio1, you need to register the Radio1 as ClientValidator attribute. You can do some C# code like this.

protected void Page_Load(object sender, EventArgs e)
{
    this.Page.ClientScript.RegisterExpandoAttribute(customCheck.ClientID, "Radio1", this.radio1.ClientID, false);
    this.Page.ClientScript.RegisterExpandoAttribute(customCheck.ClientID, "Radio2", this.radio2.ClientID, false);
    this.Page.ClientScript.RegisterExpandoAttribute(customCheck.ClientID, "Radio3", this.radio3.ClientID, false);
    this.Page.ClientScript.RegisterExpandoAttribute(customCheck.ClientID, "Radio4", this.radio4.ClientID, false);
}

And the ASPX Code is like this

<asp:CustomValidator runat="server" ID="customCheck" ClientValidationFunction="ValidateRadioButtons"
        ErrorMessage="Choose any option" />

And here is the Output code generated for the custom validator.

Custom validator output rendering

Custom validator output rendering

Happy Coding.

Implementing Paging in SQL Server 2005 Stored Procedures

April 29th, 2010 Anuraj P No comments

Normally for implementing Paging in Grid View, we enable the Paging property in GridView and will write code in the PageIndex Changed event. But the problem with this approach is it will fetch all the data from Database for Paging, will result wastage of network bandwidth and resources, also affect in the Page Performance. In SQL Server 2005 Microsoft introduced a new concepts called Row_Number() and Derived Table with the help these two we can move the Paging logic to Database instead of ASP.Net web forms. This concept also works with custom paging implementations for DataList or Repeater controls.

CREATE PROCEDURE usp_GetContacts
(@Page INT, @RecsPerPage INT)
AS
SELECT tblContacts.[Name], tblContacts.[IsParent] FROM
(SELECT ROW_NUMBER() OVER(ORDER BY [ID]) AS RowNumber,
[Name], [IsParent] FROM [TreeView].[dbo].[Contacts]) tblContacts
WHERE RowNumber > @RecsPerPage*(@Page) AND RowNumber <= @RecsPerPage*(@Page+1)

In this code we are creating a Column called “RowNumber”. And we are comparing the input parameters with the derived table tblContacts.

Thanks to Aneesh / Prasanth for their valueable suggestions and comments.

Deploying WCF Service in IIS : no svc MIME Type

April 23rd, 2010 Anuraj P No comments

Few days back I developed a Silverlight application, which uses a WCF Service to communicate to Database. After the development when I tried to deploy the WCF Service on my IIS, it was displaying some error like

Server Error in Application “Default Web Site/SampleApp”
HTTP Error 404.3 – Not Found
Description: The page you are requesting cannot be served because of the Multipurpose Internet Mail Extensions (MIME) map policy that is configured on the Web server. The page you requested has a file name extension that is not recognized, and is not allowed.
Error Code: 0×80070032
Notification: ExecuteRequestHandler
Module: StaticFileModule
Requested URL: http://localhost:80/SampleApp/CoreService.svc
Physical Path: C:\Users\Documents\Visual Studio 2005\Projects\SampleApp\SampleApp\CoreService.svc
Logon User: Anonymous
Logon Method: Anonymous
Handler: StaticFile

I tried IIS MimeTypes and I couldn’t found an application mapping for SVC file. After doing some searching I found the fix. It is happening because of not registering the WCF in IIS. You can resolve this using WCF Installation utility which comes with .Net Framework 3.0. Run the command prompt as Administrator, go to the Windows Communication Foundation folder in c:\Windows\Microsoft.NET\Framework\v3.0\ folder. Execute the servicemodelreg.exe with -i or /i switch. After the installation try reloading the Page. It will fix this issue.