views:

19

answers:

1

I am learning Fluent NHibernate and this issue arose from that project.

I have a base Class and a base Interface:

public abstract class Base : IBase
{
    public virtual Guid Id { get; set; }
    public virtual bool IsValid()
    {
        return false;
    }
}

public interface IBase
{
    Guid Id { get; set; }
    bool IsValid();
}

which I inherit all of my other Domain classes from:

public class Item:Base, IItem
{
    public virtual string Name { get; set; }

    public override bool IsValid()
    {
        <snip>
    }
    <snip>
}

public interface IItem: IBase
{
    string Name { get; set; }
    <snip>
}

However when I try and bind a list of all Items to a winforms Combobox I get an error.

        var ds = from i in GetSession().Linq<IItem>() select i;
        cmbItems.DataSource = ds.ToArray();

        this.cmbItems.DisplayMember = "Name";
        this.cmbItems.ValueMember = "Id";

I get an error:

Cannot bind to the new value member. Parameter name: value

I have figured out that this occurs because I am implementing IBase on IItem. If I modify IItem it works fine.

public interface IItem: IBase
{
    Guid Id { get; set; }
    string Name { get; set; }
    <snip>
    bool IsValid();
}

So beyond the practical, just make it work, am I doing interfaces correctly? Should I not have interfaces implement other interfaces? If I should have IItem implement IBase, is there a way to bind properly to a Winforms control?

+1  A: 

I think that's because WinForms binding system is based on the use of TypeDescriptor, and TypeDescriptor.GetProperties(typeof(IItem)) returns only the declared properties... So the ComboBox finds Name because it's declared in IItem, but not Id.

To work around this problem, you could create an anonymous type with the properties you need:

    var ds = from i in GetSession().Linq<IItem>() select new { i.Id, i.Name };
    cmbItems.DataSource = ds.ToArray();

    this.cmbItems.DisplayMember = "Name";
    this.cmbItems.ValueMember = "Id";

Anyway, I don't think you should redeclare Id and IsValid in IItem, because it would hide the properties declared in IBase (the compiler gives you a warning when you do that)

Thomas Levesque
@Thomas, I tried doing an anonymous type, but I get an error "Object must implement IConvertible", at ds.ToArray(); Any idea's?
Nathan Koop
It works fine for me, using a collection rather than a NHibernate query... I think it's because `Linq<T>` returns an `IQueryable<T>`, so it tries to execute the projection in SQL. Try to replace `Linq<IItem>()` with `Linq<IItem>().AsEnumerable()`
Thomas Levesque
Thanks Thomas, works like a charm
Nathan Koop