Showing posts with label c#. Show all posts
Showing posts with label c#. Show all posts

Sunday, May 8, 2011

Using DataAnnotations to validate entities

In every sample on the internet regarding MVC and Entity Framework 4.0, we can find the use of DataAnnotations.

DataAnnotations allows us to add to our entities some Meta data including simple rules of validation (as well as hiding column, defining display name etc.).
By simple validation rules I mean we can define:
- Required fields
- String Length
- Range

Adding DataAnnotations is quite simple, after adding a reference to System.ComponentModel.DataAnnotations, we can add a partial class extending the relevant entity from our Entity Framework edmx and defining a metadatatype class with the rules.
For example:

    [MetadataType(typeof(TrackMetaData))]
    public partial class Track
    {
        public class TrackMetaData
        {
            [ScaffoldColumn(false)]
            [DisplayName("Track Id")]
            public int Id { get; set; }

            [StringLength(50)]
            public string Name{ get; set; }

            [Range(typeof(DateTime), "1/1/1753", "31/12/9999",
               ErrorMessage = "Value for {0} must be between {1} and {2}")]
            [DisplayName("Play Date")]
            public Nullable PlayDate { get; set; }
        }
    }
}

In this example we can see the use of ScaffoldColumn, StringLegth, DisplayName & Range...for those who work on multi language system or just prefer - you can retrieve the error message from a resource file as well.

Adding this class will work for MVC, MVC's plumbing will use this class to show error messages when relevant...but what if we have another type of client and we want to make sure data is validated before saving it to database?

Add this simple helper class to your project (or even better to your framework/core/library):
   public class ValidationHelper
    {
        /// 
        /// Check if specified object is valid
        /// 
        /// The object to validate        /// 
        public static bool IsValid(object obj)
        {
            return (!Validate(obj).Any());
        }

        /// 
        /// Validate an object against Data Annotations meta data defined against the object 
        /// 
        /// The object to validate        /// A List of  
        public static List Validate(object obj)
        {
            Type instanceType = obj.GetType();
            Type metaData = null;
            MetadataTypeAttribute[] metaAttr = (MetadataTypeAttribute[])instanceType.GetCustomAttributes(typeof(MetadataTypeAttribute), true);

            if (metaAttr.Count() > 0)
            {
                metaData = metaAttr[0].MetadataClassType;
            }
            else
            {
                throw new InvalidOperationException("Cannot validate object, no metadata assoicated with the specified type");
            }

            TypeDescriptor.AddProviderTransparent(
            new AssociatedMetadataTypeTypeDescriptionProvider(instanceType, metaData), instanceType);

            List results = new List();
            ValidationContext ctx = new ValidationContext(obj, null, null);

            bool valid = Validator.TryValidateObject(obj, ctx, results, true);
            return results;
        }

        /// 
        /// Get Validation errors as string
        /// 
        /// The object to validate        /// 
        public static string GetValidationErrors(object obj)
        {
            List errors = Validate(obj);

            var errorText = new StringBuilder();
            foreach (var error in errors)
            {
                errorText.Append(error.ErrorMessage + Environment.NewLine);
            }
            return errorText.ToString();
        }
    }

Than..add a few lines of code to your UnitOfWork (see my previous post for details: EF4 Self Tracking Entities & Repository design pattern)

    public class UnitOfWork:IUnitOfWork, IDisposable
    {

        public void ApplyChanges(string entityName, object entity)
        {
            if (entity == null)
                return;

            if (entity is IObjectWithChangeTracker)
            {
                bool ok = ValidationHelper.IsValid(entity);

                if (!ok)
                {
                    string message = string.Format("Can not apply changes to the '{0}' entity due to validation errors", entity.ToString());
                    LogUtil.LogInfo(string.Format("{0} ({1})", message, ValidationHelper.GetValidationErrors(entity)));

                    throw new ValidationException(message);
                }

                _context.ApplyChanges(entityName, (IObjectWithChangeTracker)entity);
            }
            else
            {
                throw new ArgumentException("entity must implement IObjectWithChangeTracker to use applyChanges");
            }
        }
    }

That's it..before the save of every entity (you implemented a MetadataType class for), it will validate the object and refuse to applyChanges or any other policy you decide is suitable to your project.

Happy validation,
Diego

Thursday, April 7, 2011

EF4 Self Tracking Entities & Repository design pattern

Today I'm going to talk about a new sample project I was building these days just to get to know Entity Framework 4.0 better.

After reading Mark Mishaev's post here (Building N-Tier Applications with Entity Framework 4) & a few of his references I decided to explore the self tracking entities.

As I see it, Self tracking entities is one of the most basic features the previous version of EF was missing.

Self tracking entities as the name implies is the ability of our entities to contain their state, if you're familiar with datasets & their diffgram capability than you probably used the RowState property to detect which rows are new, which are updated, deleted or unchanged - that is what tracking means.

With STE (self tracking entities) you can send your entities to your client & when receiving it back, detect easily all the changes your client made and save it to your database (of course after choosing the right concurrency strategy for your application), without it - you'll find yourself comparing the returned entity with your database to decide which changes were made & setting their state one by one before you can actually save.

So STE is the ultimate solution? Not for sure....one of the big disadvantages of STE is the fact that your client must know the actual entity - meaning:
1. It will work only if you code both the server & client (it's not always the case), proxies passing the entity's datamembers won't do the tracking stuff...
2. Your client must be .net client.
3. Any changes to entity structure/logic will require client publishing (a big minus architecturally speaking).

If you're absolutely sure you can ignore these disadvantages in your specific application - you will gain a simple & great way to track changes out of the box.

Searching for the best way to implement the use of EF I encounter many discussions about a few related patterns, the two that repeatedly stood out were Repository & UnitOfWork.

To make a long reading short..

Repository will help us separating our business logic layer from knowing anything about entity framework - potentially can allow us to control our dataAccess layer behavior (cache, trace, security etc) better and change the implementation without changing the whole application, it will also allow us to replace the repository with an in-memory repository which can be a great way to unit test our application without a database.

namespace Dieg.Framework.DataAccess
{
    public interface IRepository
    { 
        T GetById(int id);
        IEnumerable GetAll();
        IEnumerable Query(Expression<Func<T, bool>> filter);
        void Add(T entity);
        void Remove(T entity);

        void ApplyChanges(T entity);
    }
}

Implementation:

namespace Dieg.Framework.DataAccess
{
    public abstract class Repository : IRepository where T : class
    {
        protected IObjectSet _objectSet;
        protected IUnitOfWork _uow;

        public Repository(IUnitOfWork uow) 
        {
            _uow = uow;
            _objectSet = _uow.CreateObjectSet();
        }

        public abstract T GetById(int id);

        public IEnumerable GetAll()
        {
            return _objectSet;
        }

        public IEnumerable Query(System.Linq.Expressions.Expression<Func<T, bool>> filter)
        {
            return _objectSet.Where(filter);
        }

        public void Add(T entity)
        {
            _objectSet.AddObject(entity);
        }

        public void Remove(T entity)
        {
            _objectSet.DeleteObject(entity);
        }

        public abstract string Name
        {
            get;
        }

        public abstract void ApplyChanges(T entity);
    }
}

Implementing a specific repository, I prefer implementing a separate repository for each entity this way we can choose a unique behavior for each entity (for example: not all entities allow all CRUD operations, maybe there are different authorization rules for some entities etc).

namespace Dieg.MusicLibrary.DataAccess
{
    public class ArtistRepository:Repository
    {
        public const string ENTITY_NAME = "Artist"; 

        public ArtistRepository(UnitOfWork uow):base(uow)
        { }

        public override Artist GetById(int id)
        {
            return _objectSet.SingleOrDefault(a => a.Id == id);
        }

        public override string Name
        {
            get { return ENTITY_NAME; }
        }


        public override void ApplyChanges(Artist entity)
        {
            _uow.ApplyChanges(Name, entity);
        }
    }
}

UnitOfWork - according to Martin Fowler, the Unit of Work pattern "maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems." (The Unit Of Work Pattern And Persistence Ignorance).

namespace Dieg.Framework.DataAccess
{
    public interface IUnitOfWork
    {
        IObjectSet CreateObjectSet() where T : class;

        void SaveChanges();

        void ApplyChanges(string entityName, object entity);
    }
}

ApplyChanges method will contain the STE implementation of updating our entities state, since ApplyChanges is per entity, we can control in our BL which entities should be influenced by the specific BL method and avoid saving irrelevant changes.

Notice the implementation will have to be in the dataAcess layer project & not part of the 'framework/core/lib', since we want it to use the STE specific context extensions.

namespace Dieg.MusicLibrary.DataAccess
{
    public class UnitOfWork:IUnitOfWork, IDisposable
    {
        private readonly DiegMusicLibraryContainer _context;

        public UnitOfWork()
        {
            _context = new DiegMusicLibraryContainer();
        }
        
        public void SaveChanges()
        {
            _context.SaveChanges();
        }

        public void Dispose()
        {
            _context.Dispose();
        }

        public IObjectSet CreateObjectSet() where E : class
        {
            return _context.CreateObjectSet();
        }

        public void ApplyChanges(string entityName, object entity)
        {
            if (entity is IObjectWithChangeTracker)
            {
                _context.ApplyChanges(entityName, (IObjectWithChangeTracker)entity);
            }
            else
            {
                throw new ArgumentException("entity must implement IObjectWithChangeTracker to use applyChanges");
            }
        }
    }
}


As I mentioned earlier, when using STE the client must have a reference to the entities, so we'll have to separate the entities from the EF context & edmx code, this can easily done using T4 templates (see :How to Separate Self-Tracking Entities to Their Own Class Library (by Gil Fink)).

Let's code a simple test to see the basic concept:

static void Main(string[] args)
        {
            Artist artist;
            
            using (UnitOfWork uow = new UnitOfWork())
            {
                ArtistRepository Artists = new ArtistRepository(uow);

                foreach (var Artist in Artists.GetAll())
                {
                    Console.WriteLine(Artist.Name);
                }
                
                artist = Artists.GetById(1);

            }

            /*unitOfWork (which holds the objectContext) is disposed here
            this will happen also when sending objects through a
              WCF (or similar) service
            */

            //change something...
            artist.ChangeTracker.ChangeTrackingEnabled = true;
            artist.Name = string.Concat(artist.Name,"AAA");


            using (UnitOfWork uow2 = new UnitOfWork())
            {
                ArtistRepository Artists = new ArtistRepository(uow2);

                //calling ApplyChanges will update the state of the artist
                //using behind the scense the STE Changetracker
                //without this the save won't recognize any changes -
                // comment the following line & try it out!!
                Artists.ApplyChanges(artist);

                uow2.SaveChanges();

                Artist b = Artists.GetById(1);
                Console.WriteLine(b.Name);
            }

            Console.ReadLine();
        }

Good luck!
Diego

Thursday, December 23, 2010

ComboBox SelectedValueChanging Event

Introduction

For some reason, a standard WinForm ComboBox does not contain SelectedValueChanging event, which may be useful if you're requested to intercept a change or cancel it.

After searching for a possible solution on the web, I've found a nice example and adopted it with slight modifications.


SelectedValueChanging Event

Generally, subclassing common WinForm controls is a good idea, since it allows you to customize their appearance and behavior in a single place and affect all instances in the entire application.

In this case, we will subclass a ComboBox class and add the SelectedValueChanging event:


public partial class nessComboBox : ComboBox
{
public event CancelEventHandler SelectedValueChanging;

private object m_LastAcceptedSelectedValue;
private bool m_IgnoreNullPreviousValueChanging = false;

public nessComboBox()
{
InitializeComponent();
}

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
public object LastAcceptedSelectedValue
{
get { return m_LastAcceptedSelectedValue; }
private set { m_LastAcceptedSelectedValue = value; }
}

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
public bool IgnoreNullPreviousValueChanging
{
get { return m_IgnoreNullPreviousValueChanging; }
set { m_IgnoreNullPreviousValueChanging = value; }
}

protected void OnSelectedValueChanging(CancelEventArgs e)
{
if (SelectedValueChanging != null)
SelectedValueChanging(this, e);
}

protected override void OnSelectedValueChanged(EventArgs e)
{
if (SelectedValueChanging != null)
{
if ((!m_IgnoreNullPreviousValueChanging ||
LastAcceptedSelectedValue != null) &&
(LastAcceptedSelectedValue ?? string.Empty).ToString()
!= (SelectedValue ?? string.Empty).ToString())
{
CancelEventArgs cancelEventArgs = new CancelEventArgs();
OnSelectedValueChanging(cancelEventArgs);

if (!cancelEventArgs.Cancel)
{
LastAcceptedSelectedValue = SelectedValue;
base.OnSelectedValueChanged(e);
}
else
SelectedValue = LastAcceptedSelectedValue;
}
else if (m_IgnoreNullPreviousValueChanging &&
LastAcceptedSelectedValue == null
&& SelectedValue != null)
{
LastAcceptedSelectedValue = SelectedValue;
}
}
else
{
base.OnSelectedValueChanged(e);
}
}
}


As you can see, the overrided OnSelectedValueChanged method performs all required logic: checks if there are subscribers to the new event and raises it before calling of the OnSelectedValueChanged method.

The variable m_IgnoreNullPreviousValueChanging may be used to ignore the initial selection change from null to some specific value in case of data-binded combo.

That's it,
Mark.

Tuesday, December 7, 2010

Custom Binding with INotifyPropertyChanged Interface

Introduction

In this post I would like to show a simple example of using INotifyPropertyChanged interface for binding a custom object properties to WinForm controls.

According to Microsoft's documentation INotifyPropertyChanged interface is used to notify clients about properties value changes.

The underneath idea is very simple: implementing this interface, forces raising PropertyChange event, which in-turn notifies client that binded property has changed.

The Example

Let's start with building a simple BankAccount class :



public class BankAccount : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

private decimal m_Balance;
private decimal m_CreditLimit;

public BankAccount(decimal initialBalance)
{
this.m_Balance = initialBalance;
this.m_CreditLimit = initialBalance * 2;
}

public decimal Balance
{
get { return m_Balance; }
}

public decimal CreditLimit
{
get { return m_CreditLimit; }
}

public void Withdrawal(decimal sum)
{
if (sum <= m_Balance)
{
m_Balance -= sum;
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs("Balance"));
}
}
}

public void Deposit(decimal sum)
{
if (sum > 0)
{
m_Balance += sum;
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs("Balance"));
}

if(m_Balance >= m_CreditLimit)
{
m_CreditLimit = m_Balance * 2;
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs("CreditLimit"));
}
}
}
}

}

The class contains two properties "Balance" and "CreditLimit" which are going to be binded to our simple UI elements:



Here is the code demonstrating how we actually bind it:


public partial class MainForm : Form
{
private BankAccount m_Account;

public MainForm()
{
InitializeComponent();
m_Account = new BankAccount(1000);

BindControls();
}

private void BindControls()
{
txtBalance.DataBindings.Add("Text",
m_Account,
"Balance",
true,
DataSourceUpdateMode.OnPropertyChanged);

txtCreditLimit.DataBindings.Add("Text",
m_Account,
"CreditLimit",
true,
DataSourceUpdateMode.OnPropertyChanged);
}

private void btnWithdrawal_Click(object sender, EventArgs e)
{
m_Account.Withdrawal(decimal.Parse(txtSum.Text));
}

private void btnDeposit_Click(object sender, EventArgs e)
{
m_Account.Deposit(decimal.Parse(txtSum.Text));
}
}


Now, the binded textboxes will automatically reflect changes of "Balance" and "CreditLimit" properties after calling Withdrawal/Deposit methods:




The working example could be downloaded here.

This is it,

Mark

Monday, September 20, 2010

Displaying images from a database - MVC style

Exploring MVC 2 I started a small project that included displaying images from my database, I know this is quite the basics, but I was impressed of the simplicity & elegant style this simple task gets when using MVC.

In the database I have a table that includes images contained in varbinary(max) column.

CREATE TABLE [dbo].[Album](
[AlbumId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NOT NULL,
[Picture] [varbinary](max) NULL,
...
...
CONSTRAINT [PK_Album] PRIMARY KEY CLUSTERED 
(
[AlbumId] ASC
)


Next in my data access layer I've added a linq query to retrieve an image by albumId.

public byte[] GetAlbumCover(int albumId)
{
var q = from album in _db.Album
where album.AlbumId == albumId
select album.Picture;

byte[] cover = q.First();

return cover;
}


As for the actual MVC...

The controller:
public ActionResult RetrieveImage(int id)
{
byte[] cover = _BL.GetAlbumCover(id);

if (cover != null)
return File(cover, "image/jpg");

return null;
}


The view:
<% foreach (var item in Model) { %>

<tr>
<td>
<%: item.ArtistName %>
</td>
<td>
<%: item.AlbumName %>
</td>
<td>
<img src="/MusicInfo/RetrieveImage/<%:item.AlbumId%>"  alt="" height=100 width=100/>
</td>
<td>
<%: Html.ActionLink("Edit", "Edit", new {id=item.AlbumId}) %>
</td>
</tr>

<% } %>


The link of the picture points to the controller (MusicInfo), the method inside the controller (RetrieveImage) & the specific image id to be able to retrieve it.

That's it...simple yet elegant.

Till next time
Diego

Tuesday, September 14, 2010

Import/Export DataSet to Excel file with ADO.NET

Often it is necessary to Import/Export DataSet to external databases or external file. Here I will present how Import/Export DataSet to excel file (*.xls or *.xlsx) with ADO.NET.
The most significant advantage of this method is that excel installation is not necessary on running station.

You will first need a connection string to connect to the Excel Workbook, which would be the following:
Excel 8 (Excel 1997):
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\MyExcel.xls;Extended Properties="Excel 8.0;HDR=YES";
Excel 12 (Excel 2007):
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:\MyExcel.xlsx;Extended Properties="Excel 12.0;HDR=YES";
Implementation of Import:
public static DataSet ImportFromExcel(string connectionString, string fileName)
{
DataSet returnDS = new DataSet();

string excelConnectionString = string.Format(connectionString, fileName);
string[] excelSheets = getExcelSheetNames(excelConnectionString);

DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OleDb");
DbDataAdapter adapter = factory.CreateDataAdapter();

using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = excelConnectionString;

foreach (string excelSheet in excelSheets)
{
DbCommand selectCommand = factory.CreateCommand();
selectCommand.CommandText = string.Format("SELECT * FROM [{0}]", excelSheet);

selectCommand.Connection = connection;
adapter.SelectCommand = selectCommand;

DataTable dt = new DataTable(excelSheet.Remove(excelSheet.Length - 1, 1));
adapter.Fill(dt);
returnDS.Tables.Add(dt);
}
}
return returnDS;
}
Implementation of Export:
public static void ExportToExcel(DataSet dataSet, string connectionString, string fileName)
{
if (dataSet != null && dataSet.Tables.Count > 0)
{
using (OleDbConnection connection = new OleDbConnection(string.Format(connectionString, fileName)))
{
OleDbCommand command = null;
connection.Open();

foreach (DataTable dt in dataSet.Tables)
{
command = new OleDbCommand(getCreateTableCommand(dt), connection);
command.ExecuteNonQuery();

for (int rowIndex = 0; rowIndex <>
{
command = new OleDbCommand(getInsertCommand(dt, rowIndex), connection);
command.ExecuteNonQuery();
}
}
}
}
}
How to use:
Lets define 2 variables:
string connectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=""Excel 8.0;HDR=YES""";
string fileName = @"C:\MyExcel.xls";
Import:
DataSet ds = ImportFromExcel(connectionString, fileName);
Export:
ExportToExcel(ds, connectionString, fileName);


Thursday, July 29, 2010

Scanning images using WIA and TWAIN

Introduction

The development of windows imaging applications requires choosing an API to communicate with scanner s or cameras. The most used APIs are WIA and TWAIN.

The WIA (Windows Image Acquisition) platform enables imaging/graphics applications to interact with imaging hardware and standardizes the interaction between different applications and scanners. This allows those different applications to talk to and interact with those different scanners without requiring the application writers and scanner manufactures to customize their application or drivers for each application-device combination. (http://msdn.microsoft.com/en-us/library/ms630368(VS.85).aspx)

TWAIN is a standard software protocol and applications programming interface (API) that regulates communication between software applications and imaging devices such as scanners and digital cameras. (http://www.twain.org/)

Differences:

1. WIA uses a common dialog for all devices while TWAIN uses a dialog created by the device manufacturer. Practically speaking, this almost always means that the TWAIN dialog will provide more options and advanced control over the device.
2. TWAIN allows you to use custom capabilities that the device manufacturer has created even though they don't exist in the TWAIN specifications.
3. In general, when a device supports both Twain and WIA, TWAIN is better for scanners and WIA is better for acquiring images from cameras and video devices.
4. TWAIN has three transfer modes (Native, Memory, File) and WIA only has two (Memory, File).
5. Most TWAIN sources save the settings of the previous scan while WIA does not.
6. TWAIN supports options for each page when scanning in duplex mode but WIA uses the same settings for both sides.

Problem

Usually, older scanners (drivers) are build for TWAIN and does not supported by WIA platform, moreover newer devices which created under Microsoft standard does not supported by TWAIN API.


In order to build scanning application that will communicate with both types of devices I combined those APIs under a uniform interface which will provide the easy access to both type of devices.

ScannerAdapterBase
public abstract class ScannerAdapterBase
{
protected List<Image> m_ImagesList = null;
protected ScannerDeviceData m_ScannerDeviceData = null;
// Initializes the Adapter
public abstract void InitAdapter(nessScanning control, IMessageFilter messageFilter, IntPtr handle);
// Selects scanning device, and returns the indicator that the device selected
// Returns the indicator that the device selected
public abstract bool SelectDevice();
// Acquires images from scanning device and fills ImagesLis
public abstract void AcquireImages(bool showUI);
}
Factory Method
public static ScannerAdapterBase GetScannerAdapter(nessScanning control, IMessageFilter messageFilter, IntPtr handle)
{
lock (locker)
{
bool isTwainDeviceSelected = false;

if (m_ScannerAdapterBase != null)
{
return m_ScannerAdapterBase;
}

try
{
//Checks WIA Devices
m_ScannerAdapterBase = new WiaScannerAdapter();
m_ScannerAdapterBase.InitAdapter(control, messageFilter, handle);
isWiaDeviceSelected = m_ScannerAdapterBase.SelectDevice();
if (isWiaDeviceSelected)
{
return m_ScannerAdapterBase;
}

//Checks TWAIN Devices
m_ScannerAdapterBase = new TwainScannerAdapter();
m_ScannerAdapterBase.InitAdapter(control, messageFilter, handle);
isTwainDeviceSelected = m_ScannerAdapterBase.SelectDevice();
if (isTwainDeviceSelected)
{
return m_ScannerAdapterBase;
}
}
catch (ScannerException ex)
{
throw ex;
}

return null;
}
}
Wia Adapter AcquireImages method
public override void AcquireImages(bool showUI)
{
CommonDialogClass wiaCommonDialog = new CommonDialogClass();

//Select Device
if (m_DeviceID == null)
{
Device device = null;
try
{
device = wiaCommonDialog.ShowSelectDevice(WiaDeviceType.ScannerDeviceType, false, false);
if (device != null)
{
m_DeviceID = device.DeviceID;
FillDeviceData(device);
}
else
{
return;
}
}
catch (COMException ex)
{
if ((WiaScannerError)ex.ErrorCode == WiaScannerError.ScannerNotAvailable)
{
return;
}
else
{
WiaScannerException se = BuildScannerException(device, ex);
throw se;
}
}
}

//Create DeviceManager
DeviceManager manager = new DeviceManagerClass();
Device WiaDev = null;
foreach (DeviceInfo info in manager.DeviceInfos)
{
if (info.DeviceID == m_DeviceID)
{
WIA.Properties infoprop = null;
infoprop = info.Properties;
//connect to scanner
WiaDev = info.Connect();
break;
}
}

//Get Scanning Properties
WIA.Item scanningItem = null;
WIA.Items items = null;
if (showUI)
{
items = wiaCommonDialog.ShowSelectItems(WiaDev, WiaImageIntent.TextIntent, WiaImageBias.MinimizeSize, false, true, false);
}
else
{
items = WiaDev.Items;
}

if (items != null && items.Count > 0)
{
scanningItem = items[1] as WIA.Item;
}

WIA.ImageFile imgFile = null;
WIA.Item item = null;

//Prepare ImagesList
if (m_ImagesList == null)
{
m_ImagesList = new List<Image>;
}
//Start Scan
while (HasMorePages(WiaDev))
{
item = scanningItem;

try
{
//Scan Image
imgFile = (ImageFile)wiaCommonDialog.ShowTransfer(item, ImageFormat.Jpeg.Guid.ToString("B")/* wiaFormatJPEG*/, false);
byte[] buffer = (byte[])imgFile.FileData.get_BinaryData();
MemoryStream ms = new MemoryStream(buffer);
m_ImagesList.Add(Image.FromStream(ms));
imgFile = null;
}
catch (COMException ex)
{
if ((WiaScannerError)ex.ErrorCode == WiaScannerError.PaperEmpty)
{
break;
}
else
{
WiaScannerException se = BuildScannerException(WiaDev, ex);
throw se;
}
}
catch (Exception ex)
{
WiaScannerException se = BuildScannerException(WiaDev, ex);
throw se;
}
finally
{
item = null;
}
}
}
Wia Adapter HasMorePages method
private bool HasMorePages(Device WiaDev)
{
try
{
bool hasMorePages = false;
//determine if there are any more pages waiting
Property documentHandlingSelect = null;
Property documentHandlingStatus = null;
foreach (Property prop in WiaDev.Properties)
{
if (prop.PropertyID == WIA_PROPERTIES.WIA_DPS_DOCUMENT_HANDLING_SELECT)
documentHandlingSelect = prop;
if (prop.PropertyID == WIA_PROPERTIES.WIA_DPS_DOCUMENT_HANDLING_STATUS)
documentHandlingStatus = prop;
}
if (documentHandlingSelect != null) //may not exist on flatbed scanner but required for feeder
{
//check for document feeder
if ((Convert.ToUInt32(documentHandlingSelect.get_Value()) & WIA_DPS_DOCUMENT_HANDLING_SELECT.FEEDER) != 0)
{
hasMorePages = ((Convert.ToUInt32(documentHandlingStatus.get_Value()) & WIA_DPS_DOCUMENT_HANDLING_STATUS.FEED_READY) != 0);
}
}
return hasMorePages;
}
catch (COMException ex)
{
WiaScannerException se = BuildScannerException(WiaDev, ex);
throw se;
}
}
TWAIN Adapter AcquireImages method
public ArrayList TransferPictures()
{
ArrayList pics = new ArrayList();
if (srcds.Id == IntPtr.Zero)
{
return pics;
}
TwRC rc;
IntPtr hbitmap = IntPtr.Zero;
TwPendingXfers pxfr = new TwPendingXfers();

do
{
pxfr.Count = 0;
hbitmap = IntPtr.Zero;

TwImageInfo iinf = new TwImageInfo();
rc = DSiinf(appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf);
if (rc != TwRC.Success)
{
CloseSrc();
return pics;
}
rc = DSixfer(appid, srcds, TwDG.Image, TwDAT.ImageNativeXfer, TwMSG.Get, ref hbitmap);
if (rc != TwRC.XferDone)
{
CloseSrc();
return pics;
}
rc = DSpxfer(appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.EndXfer, pxfr);
if (rc != TwRC.Success)
{
CloseSrc();
return pics;
}
pics.Add(hbitmap);
}
while (pxfr.Count != 0);

rc = DSpxfer(appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.Reset, pxfr);
return pics;
}

Monday, June 28, 2010

Compare two object's values

Recently we encounter an event that receives two objects and we wanted to compare their values (before and after of a column 'changing' event on a datatable). Using '==' doesn't do the work because the implementation of '==' in object compares the actual reference and not the values.

This simple method does the work.

static bool CompareObjectsValues(object a, object b)
{
if (a.GetType()!=b.GetType() 
|| !(a is IComparable) || !(b is IComparable))
return false;

IComparable valA = a as IComparable;
IComparable valB = b as IComparable;

return (valA.CompareTo(valB) == 0);

}


Full sample to show the problem and test:
static bool Compare(object a, object b)
{
return (a == b);
}

static void Main(string[] args)
{
object a = new object();
object b = new object();

DateTime d1 = new DateTime(2010, 6, 27);
DateTime d2 = new DateTime(2010, 6, 27);

a = d1;
b = d2;

object c = a;


//returns 'true' -> same reference
Console.WriteLine(Compare(a , c)); 
//returns 'false'-> same value but not same reference -> problem
Console.WriteLine(Compare(a , b)); 
//returns 'true' -> compares values and not references
Console.WriteLine(CompareObjectsValues(a, b));

}


That's it...
Diego

Thursday, June 17, 2010

Working with LayoutEngine

When you developing your custom controls sometime it requires a certain behavior or graphical representation of it child controls .
In this case you Control have a property called LayoutEngine
Example below shows you how to implement your LayoutEngine 

     public class DemoPanel : Panel
    {
        private bool m_CustomLayout = false;
        private DemoPanelLayout layoutEngine = new DemoPanelLayout();

        public DemoPanel() { }
        public bool CustomLayout
        {
            get { return m_CustomLayout; }
            set { m_CustomLayout = value; }
        }
        public override LayoutEngine LayoutEngine
        {
            get
            {
                return layoutEngine;
            }
        }
      }
Now for the custom LayoutEngine implementation


    public class DemoPanelLayout : LayoutEngine
    {
        public override bool Layout(
            object container,
            LayoutEventArgs layoutEventArgs)
        {

            Control parent = container as Control;
            if (((parent as DemoPanel).CustomLayout))
            {           
             Rectangle parentDisplayRectangle = parent.DisplayRectangle;
             Point nextControlLocation = parentDisplayRectangle.Location;
           
            foreach (Control c in parent.Controls)
            {               
                if (!c.Visible)
                {
                    continue;
                }
                if (nextControlLocation == parentDisplayRectangle.Location)
                {
                    nextControlLocation.Y += c.Margin.Top;
                    nextControlLocation.X += c.Margin.Left;
                }
              
                c.Location = nextControlLocation;
                if (!((c.Location.X + c.Width + c.Margin.Left)> (parent.Width - c.Width-c.Margin.Left)))
                {
                    nextControlLocation.Offset(c.Width+c.Margin.Left, 0 );
                }
                else
                {
                    nextControlLocation.X = parent.Left+c.Margin.Left;
                    nextControlLocation.Offset(0,c.Height+c.Margin.Top);
                }               
             }
            }
                       
            return false;
        }
    }


In example above DemoPanel's LayoutEngine will check the CustomLayout property
and order child controls as tabled view .