Found that DataSets make lousy binds for WPF forms when the data must be updated from something other than directly by the user, because datasets do not implement INotifyPropertyChanged.
Datasets are great when the data is OneWay binding, because heirarchical data relationships are so easy to define. But you've got to get creative and use something else, such as a BindingList<> when the binding must be TwoWay or OneWayToSource.
Thursday, December 3, 2009
Wednesday, December 2, 2009
XAML and the loss of Intellisense
Last week I reported losing my intellisense and tag completion on XAML pages.
I finally figured out the cause--and it's not good. I happend to start up a new solution with a single page and all of a sudden I noticed I had my Intellisense and tag completion back!
After getting all excited about it, I went back to my original solution that was having problems--Intellisense and code completion disappeared.
Yet they came back with the nothing of a solution.
Okay--I get the hint. XAML and WPF take lots and lots of RAM. I have only 2GB. From what I'm gathering, you need at least 3GB RAM.
All this only after I totally hosed up my Visual Studio trying to figure it all out.
Labels:
Intellisense,
WPF,
XAML
Tuesday, December 1, 2009
Using Syncfusion
I'll give the support team at Syncfusion credit--they do seem to respond quickly to help you out.
But I'd give the development team there a failing grade. They seem to be prone to deploy rather buggy controls for WPF use.
Seems getting "NullReferenceException" is commonplace with their controls. And I just stumbled onto a stupid one--using their DateTimeEdit control and setting the MinDateTime attribute causes the control to display "01/01/0001" as its datetime value. These kind of bugs are extremely annoying when you are trying to get a job done. They're so bad that I don't know how they get away with charging for them when so many open-source and non-buggy alternatives are available. Had I been give the ability to choose which controls to use, Syncfusion would never have been considered.
Fortunately, I stumbled onto http://wpf.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=29117. There is a DatePicker control there that'll work for me--and there's probably a large number of other controls. Especially since Syncfusion is about as crappy as it comes--try finding what you need without asking their support department--I'm going to trash the Syncfusion control usage wherever possible.
Labels:
Syncfusion,
WPF,
XAML
Friday, November 27, 2009
Syncfusion GridDataControl and referencing other columns
I was using the Syncfusion GridDataControl in WPF and needed to reference a different column from within the column I was in, so that different attributes could be set based on other columns. Found out from the SyncFusion Form support center that it's pretty easy. Just set the Binding Path as follows:
Binding Path=Record.Data.OtherColumnName
Labels:
GridDataControl,
Syncfusion,
WPF,
XAML
WPF form and debugging data
I never realized just how painful it can be to debug data that should (or should not) display on a XAML form. I bound a XAML form to a DataSet. There was a problem with one of the columns in the dataset that caused problems with the XAML form. But since there is no way to step through the debugger on the XAML, there was no way to figure out what the specific data was that was giving me problems.
The problem was solved through a Converter. I discovered you can put a breakpoint on a converter, then view your data. In my case, I had no need of a converter, so couldn't set up a breakpoint.
The solution was to add a special converter. This one did not do any actual conversion--it simply returned the passed value. But it gave me a simple way to put a breakpoint.
Below is the converter code:
class
LogObjectDataConverter : IValueConverter{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
Thursday, November 19, 2009
0x8007001f from ClickOnce install/upgrade
This has got to be the most painful thing to come across on a ClickOnce install. Error messages are almost meaningless and Google searches produce nothing useful. I'm documenting my torment in finding a solution in the event someone else comes across the same thing.
The problem was first encountered when we updated one third-party dll. The error produced during install or upgrade was :
System.Deployment.Application.InvalidDeploymentException (ManifestLoad)
- Exception occurred loading manifest from file <dllfilename>.dll: the manifest may not be valid or the file could not be opened.
- Exception occurred loading manifest from file <dllfilename>.dll: the manifest may not be valid or the file could not be opened.
Further down the log was:
System.Deployment.Application.InvalidDeploymentException (ManifestParse)
- Parsing and DOM creation of the manifest resulted in error. Following parsing errors were noticed:
- Parsing and DOM creation of the manifest resulted in error. Following parsing errors were noticed:
And finally:
System.Runtime.InteropServices.COMException
- A device attached to the system is not functioning. (Exception from HRESULT: 0x8007001F)
- A device attached to the system is not functioning. (Exception from HRESULT: 0x8007001F)
I sent an email to the third-party vendor's support department for help, and they gave me a checklist of things to try. Unfortunately, they were of the "if all else fails, blow it away and restart from scratch" nature--if the pc had other ClickOnce applications installed, they would also be blown away in following their instructions, and neither I nor they weren't even sure any of their suggestions would work. So I tried their suggestions in a much more controlled and refined approach--choosing to be more surgical in fixing the issues. I used a PC that had the old version of the application installed at one point that I didn't care about any other Click Once application it had (just in case).
Their tips:
1. Try uninstalling and reinstalling. No good--I already had the application uninstalled to start with. bogus tip.
2. Try running: mage -cc.
This clears the Application Cache. Sounds promising, but no good--same problem.
3. Delete the ClickOnce application store.
This just sounds bad--I'm certain it'll blow away all Click Once applications. I just want to clear out one ClickOnce application. Better yet--just clear out any references to the DLL I'm updating. Well, they gave these steps:
a. Make sure DFSVC.EXE process is not running. Check. It was running. They say to killing out right (from Task manager). Bummer--this might mean a reboot when done, unless I can find the Services to run to restart it.
b. Delete the application store folder %userprofile%\Local Settings\Apps. Okay, this is where I'm going to try to be a bit surgical. If being surgical fails, I'll use the nukes. I found the folders that contained copies of my old version dll and made sure the folder was for my application (even though the application was not installed), deleting the entire folder (it's not installed anyhow, so it shouldn't matter). That failed because one of the files was in use. I was able to delete the old-version dll I cared about, so that was good enough.
c. Delete folder %userprofile%\Local Settings\Apps. I don't know, but that sounds a lot like "b" above. okay--I'm moving on.
d. Delete HKCU\Software\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment. That's Regedit, and looking into it, there's a lot there. Being surgical, I went further down to \SideBySide\2.0\Components\ and found the folder for my DLL, deleting the whole folder.
I did all this and tried to install again--dfsvc did start on its own so a reboot wasn't necessary--but the install still failed. Okay, let's try bigger guns. I searched the registry for my dll underneath the Deployment key and found a few other copies (after stopping that DFSVC process). Same thing. Okay--time for the "deployment" key to be deleted. Also removing the "Apps" folder.
NOTHING WORKS!!!!
Finally gave up entirely. We determined that the third-party vendor had to be installed in the GAC anyhow to work--so we just removed the file from the project and made sure the reference was set up to use the GAC version. Problem solved.
I spent most of the day Googling and Binging for help on this--even Microsoft either didn't respond with answers on the few forums that encountered the problem, or if Microsoft did respond it was with an answer that didn't make sense--or didn't explain how you would accomplish the recommended task.
I just hope I never see this one again. But if I do--I hope the answer gets found.
Wednesday, October 28, 2009
Why Team Build won't customize app.config
I was bashing my head over app.config not getting customized upon deployment, even though I confirmed values changed in app.config before the compile step.
Then it occurred to me that I was using user settings, and that a Settings.settings file was being generated. It looks like this modifiying this file for default values is actually more important that modifying the app.config file, depending on how you are doing your settings.
Labels:
ClickOnce,
Team Build,
Team Systems
Wednesday, September 30, 2009
WIA in C# Redux: for Vista!
Of all the insanity! The scanning code I posted earlier does not work with the default configuration of Vista! Vista does not have the wiascr.dll file. However, it does have wiaaut.dll. Code I found at http://www.eggheadcafe.com/community/aspnet/2/76650/heres-some-sample-code.aspx finally gave me the answer after bashing my head around. It was easy to find code that worked for a WebCam, but nearly impossible to find code that worked for the scanner I was using. I guess no one out there uses scanners. Anyway, here's the modified code. Note that I added a ScannerException class--this just inherits the Exception class--nothing special about it:
///
/// This is a simple wrapper around WIA.
///
public class Scanner
{
public class AcquireEventArgs : EventArgs
{
public Image Image { get; internal set; }
}
WIA.DeviceManager manager = new WIA.DeviceManagerClass();
///
/// Acquires the images.
///
public void AcquireImages()
{
WIA.CommonDialogClass diag = new WIA.CommonDialogClass();
System.Object Object1 = null;
System.Object Object2 = null;
WIA.Device dev = null;
try
{
dev = diag.ShowSelectDevice(WIA.WiaDeviceType.UnspecifiedDeviceType, true, false);
}
catch (Exception ex)
{
if (ex.Message.EndsWith("00153.") || ex.Message.EndsWith("21006A."))
{
throw new ScannerException("Scanner Not connected", ex);
}
else
{
throw new ScannerException("Scanner problem", ex);
}
}
if (dev != null)
{
WIA.Item Item1 = ItemObjectReturnedFromInitializingScanner(ref dev);
WIA.ImageFile Image1 = new WIA.ImageFile();
WIA.ImageProcess ImageProcess1 = new WIA.ImageProcess();
Object1 = (Object)"Convert";
ImageProcess1.Filters.Add(ImageProcess1.FilterInfos.get_Item(ref Object1).FilterID, 0);
Object1 = (Object)"FormatID";
Object2 = (Object)WIA.FormatID.wiaFormatTIFF;
ImageProcess1.Filters[1].Properties.get_Item(ref Object1).set_Value(ref Object2);
Object1 = (Object)"Compression";
Object2 = (Object)"CCITT4";
ImageProcess1.Filters[1].Properties.get_Item(ref Object1).set_Value(ref Object2);
Object1 = null;
Object2 = null;
try
{
WIA.ImageFile imagefile = Item1.Transfer(WIA.FormatID.wiaFormatTIFF) as WIA.ImageFile;
if (ImageScanned != null)
{
AcquireEventArgs e = new AcquireEventArgs();
using (MemoryStream ms = new MemoryStream((byte[])imagefile.FileData.get_BinaryData()))
{
e.Image = new Bitmap(ms);
}
ImageScanned(this, e);
}
}
catch (Exception ex)
{
throw new ScannerException("Problem with Scanner", ex);
}
}
}
private WIA.Item ItemObjectReturnedFromInitializingScanner(ref WIA.Device Scanner)
{
WIA.Item Item1 = null;
Object Object1 = null;
Object Object2 = null;
Int32 DPI = 200;
foreach (WIA.Item CurrentItem in Scanner.Items) // 'Scanner settings.
{
Item1 = CurrentItem;
try
{
Object1 = (Object)"6146";
Object2 = (Object)4;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6147";
Object2 = (Object)DPI;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6148";
Object2 = (Object)DPI;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6149";
Object2 = (Object)0;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6150";
Object2 = (Object)0;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6151";
Object2 = (Object)(8.5 * DPI);
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6152";
Object2 = (Object)(11.5 * DPI);
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
foreach (WIA.Property Prop in Scanner.Properties)
{
if (Prop.PropertyID == 3088) //
{
try
{
Object1 = (Object)5;
Prop.set_Value(ref Object1); //'This is my effort to enforce duplex. I
}
catch (Exception) { }
}
}
}
Object1 = null;
Object2 = null;
return Item1;
}
///
/// Occurs when [image scanned].
///
public event EventHandler ImageScanned;
}
///
/// This is a simple wrapper around WIA.
///
public class Scanner
{
public class AcquireEventArgs : EventArgs
{
public Image Image { get; internal set; }
}
WIA.DeviceManager manager = new WIA.DeviceManagerClass();
///
/// Acquires the images.
///
public void AcquireImages()
{
WIA.CommonDialogClass diag = new WIA.CommonDialogClass();
System.Object Object1 = null;
System.Object Object2 = null;
WIA.Device dev = null;
try
{
dev = diag.ShowSelectDevice(WIA.WiaDeviceType.UnspecifiedDeviceType, true, false);
}
catch (Exception ex)
{
if (ex.Message.EndsWith("00153.") || ex.Message.EndsWith("21006A."))
{
throw new ScannerException("Scanner Not connected", ex);
}
else
{
throw new ScannerException("Scanner problem", ex);
}
}
if (dev != null)
{
WIA.Item Item1 = ItemObjectReturnedFromInitializingScanner(ref dev);
WIA.ImageFile Image1 = new WIA.ImageFile();
WIA.ImageProcess ImageProcess1 = new WIA.ImageProcess();
Object1 = (Object)"Convert";
ImageProcess1.Filters.Add(ImageProcess1.FilterInfos.get_Item(ref Object1).FilterID, 0);
Object1 = (Object)"FormatID";
Object2 = (Object)WIA.FormatID.wiaFormatTIFF;
ImageProcess1.Filters[1].Properties.get_Item(ref Object1).set_Value(ref Object2);
Object1 = (Object)"Compression";
Object2 = (Object)"CCITT4";
ImageProcess1.Filters[1].Properties.get_Item(ref Object1).set_Value(ref Object2);
Object1 = null;
Object2 = null;
try
{
WIA.ImageFile imagefile = Item1.Transfer(WIA.FormatID.wiaFormatTIFF) as WIA.ImageFile;
if (ImageScanned != null)
{
AcquireEventArgs e = new AcquireEventArgs();
using (MemoryStream ms = new MemoryStream((byte[])imagefile.FileData.get_BinaryData()))
{
e.Image = new Bitmap(ms);
}
ImageScanned(this, e);
}
}
catch (Exception ex)
{
throw new ScannerException("Problem with Scanner", ex);
}
}
}
private WIA.Item ItemObjectReturnedFromInitializingScanner(ref WIA.Device Scanner)
{
WIA.Item Item1 = null;
Object Object1 = null;
Object Object2 = null;
Int32 DPI = 200;
foreach (WIA.Item CurrentItem in Scanner.Items) // 'Scanner settings.
{
Item1 = CurrentItem;
try
{
Object1 = (Object)"6146";
Object2 = (Object)4;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6147";
Object2 = (Object)DPI;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6148";
Object2 = (Object)DPI;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6149";
Object2 = (Object)0;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6150";
Object2 = (Object)0;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6151";
Object2 = (Object)(8.5 * DPI);
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6152";
Object2 = (Object)(11.5 * DPI);
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
foreach (WIA.Property Prop in Scanner.Properties)
{
if (Prop.PropertyID == 3088) //
{
try
{
Object1 = (Object)5;
Prop.set_Value(ref Object1); //'This is my effort to enforce duplex. I
}
catch (Exception) { }
}
}
}
Object1 = null;
Object2 = null;
return Item1;
}
///
/// Occurs when [image scanned].
///
public event EventHandler
}
Monday, September 21, 2009
Mouse drawing in WPF
I was trying to build a simple control to allow mouse drawing via the WPF. I found one web site that seemed to make the process a bit more complicated than doing the same thing in Windows Forms--but I tried it anyhow, and I simply couldn't make it work. I don't remember the website, but it basically used a canvas, and attempted to draw shapes on it based on Mouse movements. I had implemented routines bound to MouseDown, MouseUp, and MouseMove events, but those events never seemed to execute.
Then I discovered the InkCanvas control--and that solved all my problems. That original code must have come from before the existance of the InkCanvas, or the programmer simply didn't know any better. After switching to use the InkCanvas code I could remove all event handling code so that I only needed the code to capture the resulting image and save it. Below is the XAML:
<
UserControl x:Class="RCO.Imaging.SignaturePad.MouseSignaturePad.SignaturePad"xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
HorizontalAlignment="Stretch" Width="Auto" Height="Auto" VerticalAlignment="Stretch" > <InkCanvas Name="canvas1" Width="Auto" Height="Auto" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ></InkCanvas>
</
UserControl>And here is the C# behind it:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace
MousePad{
/// <summary>
/// Interaction logic for SignaturePad.xaml
/// </summary>
public partial class SignaturePad : UserControl
{
public SignaturePad()
{
InitializeComponent();
} public static RenderTargetBitmap ToImageSource(FrameworkElement obj)
{ // Save current canvas transform
Transform transform = obj.LayoutTransform;
obj.LayoutTransform = null;
// fix margin offset as well
Thickness margin = obj.Margin;
obj.Margin = new Thickness(0, 0,
margIn.Right - margin.Left, margin.Bottom - margin.Top);
// Get the size of canvas
Size size = new Size(obj.ActualWidth, obj.ActualHeight);
// force control to Update
obj.Measure(size);
obj.Arrange(new Rect(size));
RenderTargetBitmap bmp = new RenderTargetBitmap(
(int)obj.ActualWidth, (int)obj.ActualHeight, 96, 96, PixelFormats.Pbgra32);
bmp.Render(obj);
// return values as they were before
obj.LayoutTransform = transform;
obj.Margin = margin;
return bmp;
}
public void AcceptImage()
{
using (System.IO.MemoryStream outStream = new System.IO.MemoryStream())
{
// Use png encoder for our data
PngBitmapEncoder encoder = new PngBitmapEncoder();
// push the rendered bitmap to it
encoder.Frames.Add(BitmapFrame.Create(ToImageSource(canvas1)));
// save the data to the stream
encoder.Save(outStream);
outStream.Position = 0;
// Do something with the MemoryStream here--save it to file or pass it back into system.
}
}
}
}
Thursday, September 17, 2009
WIA in C#
Been awhile. Ran into a problem of needing to write code to acquire an image from a scanner. I had done TWAIN coding, but I've found that TWAIN is now gone by the wayside--in otherwords, don't use it.
Instead, use WIA. I had found Microsoft's WIA SDK, but discovered that its examples are in VB6, to give you an idea how old the stuff is. And on top of it--it seemed a bit convoluted.
Then I ran into http://www.codeproject.com/KB/dotnet/wiascriptingdotnet.aspx, which had a good example, though a little on the incomplete side (he left off the variable declaration statements). It seemed too simple, but I tried it out.
And wouldn't you know it--that was all that was needed! The link also include video information, but that was beyond the scope of my project.
Below is my code which wraps the WIA (strongly based on the above link). All you need to do is create the Scanner object, assign the "ImageScanned" event, the call the AcquireImages method. This code works asynchronously, so you can have other things going on while you wait for the images:
using
System;using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using WIALib;
namespace WIAWrapper
{
/// <summary>
/// This is a simple wrapper around WIA.
/// </summary>
public class Scanner
{
public class AcquireEventArgs : EventArgs
{
public Image Image { get; internal set; }
}
object selectUsingUI = System.Reflection.Missing.Value;
ItemClass wiaRoot;
WIALib.WiaClass wiaManager;
public Scanner()
{
wiaManager = new WIALib.WiaClass();
wiaRoot = (ItemClass)wiaManager.Create(ref selectUsingUI);
}
/// <summary>
/// Acquires the images.
/// </summary>
public void AcquireImages()
{
List<Image> retVal = new List<Image>();
CollectionClass wiaPics = wiaRoot.GetItemsFromUI(WiaFlag.SingleImage, WiaIntent.ImageTypeColor) as CollectionClass;
wiaManager.OnTransferComplete += new _IWiaEvents_OnTransferCompleteEventHandler(wiaManager_OnTransferComplete);
foreach (object wiaObj in wiaPics)
{
ItemClass wiaItem = (ItemClass)Marshal.CreateWrapperOfType(wiaObj, typeof(ItemClass));
string imgFile = Path.GetTempFileName();
wiaItem.Transfer(imgFile, true);
}
} public event EventHandler<AcquireEventArgs> ImageScanned; /// <summary>
/// Wias the manager_ on transfer complete.
/// </summary>
/// <param name="Item">The item.</param>
/// <param name="Path">The path.</param>
void wiaManager_OnTransferComplete(Item Item, string Path)
{
if (ImageScanned != null)
{
AcquireEventArgs e = new AcquireEventArgs();
e.Image = new Bitmap(Path);
ImageScanned(this, e);
}
}
}
}
Subscribe to:
Posts (Atom)