donderdag 22 juli 2010

ASP.NET & LINQ Viewstate

A small issue I ran across when building a ASP.NET website was that a lot of pages contained LINQ datasources on them which started to tax the performance of the website. A large factor in boosting the performance was disabling the viewstate on all of the LINQ datasources. At first this resulted in a lot of exceptions whenever the datasource needed updating, which was due to LINQ using the values stored in the viewstate for version checking with the current data.

This problem was solved by adding a timestamp column to each table. If a table has a timestamp column LINQ will disable update checking on all other columns and use only the timestamp column for version checking.

woensdag 20 januari 2010

Drag & Drop

Basic drag & drop is pretty easy to accomplish in WPF. For starters you should add a MouseMove handler to the object you want to drag around. When you detect the left mouse button is pressed you initiate the drag and pass the source and data to the drag & drop method.

     private void border_PreviewMouseMove(object sender, MouseEventArgs e)
{
Border border = (Border)sender;
if (e.LeftButton == MouseButtonState.Pressed)
{
DragDropEffects dropEffect = DragDrop.DoDragDrop(border, border.Child, DragDropEffects.Move);
}
}

Any object you want to drop another object inside needs to have the 'AllowDrop' property set to true. When that's done you add a handler to handle the drop event. Inside you should check the type of the data being dropped and if it is what you expect then you can deal with it accordingly. In this case the Border object had an Image object set as its child.

     private void grdPdf_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(Image)))
{
Image image = (Image)e.Data.GetData(typeof(Image));
}
}

OCR with Microsoft Office

If you have Microsoft Office available on the platform where you're developing (for) you can accomplish OCR functionality by taking advantage of the Office dll's. All you need to do for the following code to work is to add a reference to the Microsoft Office Document Imaging Library in the COM tab.

Be aware that this library might not have been installed along with the Office apps, but you can modify your installation in the control panel to include this library.

All you have to do here is create a document from the image file you wish to analyze and select a language. You can then loop through the recognized words in the layout object of the image.

              MODI.Document doc = new MODI.Document();
doc.Create(filename);

doc.OCR(MODI.MiLANGUAGES.miLANG_ENGLISH, true, true);

MODI.Image image = (MODI.Image)doc.Images[0];
MODI.Layout layout = image.Layout;

string text = "";
for (int j = 0; j < layout.Words.Count; j++)
{
MODI.Word word = (MODI.Word)layout.Words[j];
text += " " + word.Text;
}
doc.Close(false);

Convert images to pdf

Using the Open Source library PDFsharp converting images to a PDF document becomes child's play. Just create the document, add a page, import an image and save the document to disk.

Plus PDFsharp comes with a license free of any restrictions so you can reuse it in any program for whatever purpose you like!

                OpenFileDialog openFile = new OpenFileDialog();
if (openFile.ShowDialog().Value)
{
PdfDocument pdfDoc = new PdfDocument();
pdfDoc.Pages.Add(new PdfPage());
XGraphics xGraphics = XGraphics.FromPdfPage(pdfDoc.Pages[0]);
XImage xImage = XImage.FromFile(openFile.FileName);

xGraphics.DrawImage(xImage, 0, 0);
pdfDoc.Save(@"C:\test.pdf");
pdfDoc.Close();
}

zaterdag 3 oktober 2009

Formatting source code for blogs

Since blogger does not have a code tag to support formatting of source code it would be rather troublesome to do all of this manually. Luckily Greg Houston over at http://formatmysourcecode.blogspot.com/ was kind enough to share his web app which processes your source code and outputs html which you can directly paste into your blog. Sure you lose all the pretty colors, but as soon as you paste the code into your editor you get them back anyway.

Many thanks to you, Greg.

Using resourcedictionaries to provide user customization

We start out with a resourcedictionary containing the default values in our App.xaml. This way we can reference the dictionary throughout the entire application.
<Application.Resources>
<SolidColorBrush x:Key="UserBackgroundColor" Color="White"/>
<SolidColorBrush x:Key="UserControlColor" Color="White"/>
<SolidColorBrush x:Key="UserControlFontColor" Color="Black"/>
<FontFamily x:Key="UserControlFont">Segoe UI</FontFamily>
</Application.Resources>



Let's assume we have a user object which remembers the customizations made by the user. When the user logs in his settings are loaded and all elements referencing the resourcedictionary we defined earlier will display the way the user defined.
private void MergeDictionaries(User user)
{
ResourceDictionary resourceDictionary = new ResourceDictionary();

SolidColorBrush userBackgroundColor = new SolidColorBrush(Colors.White);
if (user.BackgroundColor != null)
{
userBackgroundColor = user.BackgroundColor;
}
resourceDictionary.Add("UserBackgroundColor", userBackgroundColor);

SolidColorBrush userControlColor = new SolidColorBrush(Colors.White);
if (user.ControlColor != null)
{
userControlColor = user.ControlColor;
}
resourceDictionary.Add("UserControlColor", userControlColor);

SolidColorBrush userControlFontColor = new SolidColorBrush(Colors.Black);
if (user.ControlFontColor != null)
{
userControlFontColor = user.ControlFontColor;
}
resourceDictionary.Add("UserControlFontColor", userControlFontColor);

FontFamily userControlFont = new FontFamily("Segoe UI");
if (user.ControlFont != null && !user.ControlFont.Equals(""))
{
userControlFont = new FontFamily(user.ControlFont);
}
resourceDictionary.Add("UserControlFont", userControlFont);

Application.Current.Resources.MergedDictionaries.Add(resourceDictionary);
}



Every control referencing the resourcedictionary will display itself differently according to which user is logged in.
<TextBlock Name="txtText" 
Foreground="{StaticResource UserControlFontColor}"
FontFamily="{StaticResource UserControlFont}"
Text="Text"/>

Creating a form with moveable controls

This is part of a larger concept that involves letting users design the layout of the forms they use themselves (adding, (re)moving and saving controls). The basic setup is a canvas with stackpanels as its children which can be moved around freely. The stackpanels can contain any kind and amount of children or you can replace the stackpanels with another frameworkelement of your liking.

XAML:
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Canvas HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10" Name="canvasControls"/>
</ScrollViewer>



These three handlers handle the dragging of controls around the canvas:
private void controls_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
position = e.GetPosition(canvasControls);
StackPanel panel = (StackPanel)sender;
if (editMode)
{
panel.CaptureMouse();
}
panel.Tag = true;
SetZIndex(panel);
}

private void controls_PreviewMouseMove(object sender, MouseEventArgs e)
{
StackPanel panel = (StackPanel)sender;
if (e.LeftButton == MouseButtonState.Pressed && editMode && (bool)panel.Tag)
{
Point currentPosition = e.GetPosition(canvasControls);
double moveX = currentPosition.X - position.X;
double moveY = currentPosition.Y - position.Y;

double newX = Canvas.GetLeft(panel) + moveX;
double newY = Canvas.GetTop(panel) + moveY;

FrameworkElement element = SnapToControl(panel, newX, true);
if (element != null)
{
newX = Canvas.GetLeft(element);
}
element = SnapToControl(panel, newY, false);
if (element != null)
{
newY = Canvas.GetTop(element);
}

Canvas.SetLeft(panel, newX);
Canvas.SetTop(panel, newY);

position = currentPosition;
}
}

private void controls_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
StackPanel panel = (StackPanel)sender;
panel.Tag = false;
panel.ReleaseMouseCapture();
RedrawCanvas(panel);
}



Because a canvas has no support for sizing to its children, of course there would be problems when moving around its children inside and outside of its boundaries. The following piece of code is called when you release the mouse on the control you're dragging and recalculates the canvas' dimensions. This way the scrollviewer around the canvas can display scrollbars when needed.
private void RedrawCanvas(FrameworkElement element)
{
double minTop = 0;
double minLeft = 0;
double maxTop = 0;
double maxLeft = 0;
foreach (FrameworkElement control in canvasControls.Children)
{
double top = Canvas.GetTop(control);
double left = Canvas.GetLeft(control);

if (top < minTop)
{
minTop = top;
}
if (top > maxTop)
{
maxTop = top;
}
if (left < minLeft)
{
minLeft = left;
}
if (left > maxLeft)
{
maxLeft = left;
}
}
if (minTop < 0)
{
foreach (FrameworkElement control in canvasControls.Children)
{
Canvas.SetTop(control, Canvas.GetTop(control) + Math.Abs(minTop));
}
}
if (minLeft < 0)
{
foreach (FrameworkElement control in canvasControls.Children)
{
Canvas.SetLeft(control, Canvas.GetLeft(control) + Math.Abs(minLeft));
}
}
canvasControls.Width = maxLeft + element.Width;
canvasControls.Height = maxTop + element.Height;
}



This method makes the control you're dragging the topmost one among the canvas' children so you're not dragging the control around below others.
private void SetZIndex(FrameworkElement control)
{
int z = 0;
foreach (FrameworkElement element in canvasControls.Children)
{
if (!element.Name.Equals(control.Name))
{
Canvas.SetZIndex(element, z++);
}
}
Canvas.SetZIndex(control, z);
}



Finally this method is used to provide snapping functionality to more easily align your controls on the canvas. It searches for controls positioned within the proximity of the control being moved. The snap distance determines how many pixels you must move your mouse cursor at once to 'snap out' of the hold again.
private FrameworkElement SnapToControl(FrameworkElement sender, double newPosition, bool x)
{
double snapDistance = Properties.Settings.Default.snap;
foreach (FrameworkElement element in canvasControls.Children)
{
if (!element.Name.Equals(sender.Name))
{
double difference = 0;
switch (x)
{
case true:
difference = Canvas.GetLeft(element) - newPosition; break;
case false:
difference = Canvas.GetTop(element) - newPosition; break;
}
difference = Math.Abs(difference);
if (difference <= snapDistance && difference > 0)
{
return element;
}
}
}
return null;
}