DataSet.DataMember – it doesn’t work as expected

F

frankswildyearstom

Hello,


Q1- I know there are more efficient ways to do this ( with
SqlDatasource), but If DataSet contains two tables, I would think
DataMember property would enable us two choose the table to be
displayed:

GridView1.DataSource = ds;
GridView1.DataMember = "ds.Tables[0]";//exception
this.DataBind();


I do know we could instead try:

GridView1.DataSource = ds.Tables[0];
this.DataBind(); // works


Q2 – Unlike DataSourceID property, DataSource property can’t be set
declaratively (inside .aspx file).
Any idea why it would be a bad idea to enable setting DataSource
inside aspx file?


Q3 - GridView.DataKeyNames stores the names of the primary key fields
for the items displayed in a GridView control. So if we issue a select
statement, which populates GridView, I would expect that by the time
Selected event is raised, GridView would already create DataKey
objects and store primary key values in them.
But it doesn’t? Why - when SqlDataSource.Selected is fired, GridView
columns are already filled with data and so GridView shouldn’t have
any problems storing primary key values into DataKey objects?


thanx
 
P

Pavel Minaev

Hello,

Q1- I know there are more efficient ways to do this ( with
SqlDatasource), but If DataSet contains two tables, I would think
DataMember property would enable us two choose the table to be
displayed:

GridView1.DataSource = ds;
GridView1.DataMember = "ds.Tables[0]";//exception

DataMember should be set to the _name_ of the table in the dataset you
want to bind to. The name of the DataTable is the value of its Name
property, not a quoted C# expression. In your example, obviously,
there was no table named "ds.Tables[0]" - unsurprisingly so.
Q2 – Unlike DataSourceID property, DataSource property can’t be set
declaratively (inside .aspx file).
Any idea why it would be a bad idea to enable setting DataSource
inside aspx file?

What would you set it to, in markup?
Q3 - GridView.DataKeyNames stores the names of the primary key fields
for the items displayed in a GridView control. So if we issue a select
statement, which populates GridView, I would expect that by the time
Selected event is raised, GridView would already create DataKey
objects and store primary key values in them.
But it doesn’t? Why - when SqlDataSource.Selected is fired, GridView
columns are already filled with data and so GridView shouldn’t have
any problems storing primary key values into DataKey objects?

Can you clarify what exactly goes wrong? Do you mean that
GridView.DataKeys is empty, or what?
 
F

frankswildyearstom

hello,


Q1 - We are able to bind “Label1” at design time to a member of same
class:

<asp:Label ID="Label1" Text='<%# someWord %>' ... />

public partial class _Default : System.Web.UI.Page
{
public string someWord = "wildYears";
}


But if “someWord” is member of class “Testing”:

public class Testing
{
public string someWord=”wildYears”;
}

then:

<asp:Label ID="Label1" Text='<%# testing.someWord %>' ... />

protected void Page_Load(object sender, EventArgs e)
{
Testing testing = new Testing();
Label1.DataBind();
}

will give us a compile time error.


-- I would asume error happens because compiler demands that data
source already exists at the time “Label1” is first created?

-- But since Label1.DataBind() can happen at later time, why doesn’t
compiler look if anywhere in code an instance named “testing” is
created and if it finds that instance, then it won’t complain?


Next example is even more confusing. If we instead make “someWord” a
static member of “Testing” class

public class Testing
{
public static string someWord=”wildYears”;
}

then compiler shouldn’t complain at all, since now data source will
already exist at the time “Label1” will first be created?

<asp:Label ID="Label1" Text='<%# Testing.someWord %>' ... />



Q1- I know there are more efficient ways to do this ( with
SqlDatasource), but If DataSet contains two tables, I would think
DataMember property would enable us two choose the table to be
displayed:
GridView1.DataSource = ds;
GridView1.DataMember = "ds.Tables[0]";//exception

DataMember should be set to the _name_ of the table in the dataset you
want to bind to. The name of the DataTable is the value of its Name
property, not a quoted C# expression. In your example, obviously,
there was no table named "ds.Tables[0]" - unsurprisingly so.
If I want to bind my own custom data source to GridView( using
GridView.DataSource property ) and if this data source provides
several list of data items, then I’d imagine my data source needs to
have a property of sort to tell binding control to which list of data
items to bind to?

As an example - I could create data source class tableH, which
contains several Hashtable objects.What needs tableH to implement
( besides Hashtable objects ), so that we could tell GridView(via
DataMember) to which of hashtables to bind to? I would guess that
tableH needs a property which specifies the name of hashtable the
control should bind to, and when the time comes, GridView will check
this property and then bind to appropriate table. But what should the
name of that property be?



What would you set it to, in markup?
We should have the option of setting DataSource to a static method
that returns an object ( this object containing data items to
display )

Can you clarify what exactly goes wrong? Do you mean that
GridView.DataKeys is empty, or what?

Yes, it is empty - if we issue a select ( via SqlDataSource )
statement to populate GridView, then at the time Selected event is
raised, GridView should already be able to populate DataKeys
collections with DataKey objects. But it doesn’t. Only on the next
page postback does it create DataKey objects:

protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
Label1.Text=GridView1.DataKeys.Count.ToString();
Label2.Text= GridView1.DataKeys[0].Value.ToString();
}
}
 
P

Pavel Minaev

hello,

Q1 - We are able to bind “Label1” at design time to a member of  same
class:

<asp:Label ID="Label1"  Text='<%# someWord %>' ... />

public partial class _Default : System.Web.UI.Page
{
        public  string someWord = "wildYears";

}

But if “someWord” is member of class “Testing”:

public class Testing
{
       public string someWord=”wildYears”;

}

then:

<asp:Label ID="Label1" Text='<%# testing.someWord %>' ... />

protected void Page_Load(object sender, EventArgs e)
{
    Testing testing = new Testing();
    Label1.DataBind();

}

will give us a compile time error.

Well yes, of course. As you said yourself, you can reference _members_
of your class in inline expressions. There's no member of your class
named "testing" - there's only a local variable named "testing" in
function Page_Load. It will work if you make "testing" a field of your
page class.

Well, almost. It still won't work if you initialize it in Page_Load,
because ASP.NET markup is "executed" (in a sense of controls being
created and their properties assigned correspondingly) before Load,
and even before Init. You need to initialize in PreInit or constructor
to make it work. See "ASP.NET Page Lifecycle" for more info:

http://msdn.microsoft.com/en-us/library/ms178472.aspx
-- I would asume error happens because compiler demands that data
source already exists at the time “Label1” is first created?

-- But since Label1.DataBind() can happen at later time, why doesn’t
compiler look if anywhere in code an instance named “testing” is
created and if it finds that instance, then it won’t complain?

The compiler does not know anything about "data sources" and "data
binding" - at all. It only knows about classes and properties and
variables. As such, the question is meaningless.
Next example is even more confusing. If we instead make “someWord” a
static member of “Testing” class

public class Testing
{
       public static string someWord=”wildYears”;

}

then compiler shouldn’t complain at all, since now data source will
already exist at the time “Label1” will first be created?

<asp:Label ID="Label1"  Text='<%# Testing.someWord %>' ... />

Again, it's not at all about "data source existing". It's simply that
in this example, the _field_ someWord is visible and accessible at the
point it is used.

Note also that a data source is always some object; it is not a
variable (though you can of course use an object referenced by some
variable as a data source, which is what you're trying to do in the
examples above).
 
F

frankswildyearstom

Hello,

I know my reply is very late, but I really wasn’t able to reply any
sooner. Still, I hope it’s not too late

Q1- I know there are more efficient ways to do this ( with
SqlDatasource), but If DataSet contains two tables, I would think
DataMember property would enable us two choose the table to be
displayed:
GridView1.DataSource = ds;
GridView1.DataMember = "ds.Tables[0]";//exception
DataMember should be set to the _name_ of the table in the dataset you
want to bind to. The name of the DataTable is the value of its Name
property, not a quoted C# expression. In your example, obviously,
there was no table named "ds.Tables[0]" - unsurprisingly so.

If I want to bind my own custom data source to GridView( using
GridView.DataSource property ) and if this data source provides
several list of data items, then I’d imagine my data source needs to
have a property of sort to tell binding control to which list of data
items to bind to?

As an example - I could create data source class tableH, which
contains several Hashtable objects.What needs tableH to implement
( besides Hashtable objects ), so that we could tell GridView(via
DataMember) to which of hashtables to bind to? I would guess that
tableH needs a property which specifies the name of hashtable the
control should bind to, and when the time comes, GridView will check
this property and then bind to appropriate table. But what should the
name of that property be?

Well yes, of course. As you said yourself, you can reference _members_
of your class in inline expressions. There's no member of your class
named "testing" - there's only a local variable named "testing" in
function Page_Load. It will work if you make "testing" a field of your
page class.

Well, almost. It still won't work if you initialize it in Page_Load,
because ASP.NET markup is "executed" (in a sense of controls being
created and their properties assigned correspondingly) before Load,
and even before Init. You need to initialize in PreInit or constructor
to make it work. See "ASP.NET Page Lifecycle" for more info:

http://msdn.microsoft.com/en-us/library/ms178472.aspx

I don’t understand what you mean. In the code below I initialized
member named “testBind” inside Page_Load(), right before calling
DataBind(), and “Label1” still managed to bind with testBind and
display its value:

<asp:Label ID="Label1" Text='<%# testBind %>' ... />

public partial class _Default : System.Web.UI.Page
{
public string testBind;
private void Page_Load(object sender, EventArgs e)
{
testBind = “someWord”;
this.DataBind();
}


-- Or do you mean that data source ( testBind ) must be available at
the time Web control properties that are specified in the declarative
syntax have been assigned?

-- Are control properties that are specified in the declarative
syntax assigned right after PreInit event?



The compiler does not know anything about "data sources" and "data
binding" - at all. It only knows about classes and properties and
variables. As such, the question is meaningless.

Above code will perform data binding if I replace Text='<%#
testing.someWord %> with Text='<%# WebApplication1.Testing.someWord
%>

-- Since Testing class is defined in same assembly and in same
namespace as _aspx class, I would assume runtime would be able to find
the Testing even if I don’t specify its fully qualified name?



Again, it's not at all about "data source existing". It's simply that
in this example, the _field_ someWord is visible and accessible at the
point it is used.

Note also that a data source is always some object; it is not a
variable (though you can of course use an object referenced by some
variable as a data source, which is what you're trying to do in the
examples above).

You mean simple types ( and structs in general ) are automatically
boxed when used in data binding expression? Why?


I appreciate your help
 
P

Pavel Minaev

If  I want to bind  my own custom data source to GridView( using
GridView.DataSource property ) and if this data source provides
several list of data items, then I’d imagine my data source needs to
have a property of sort to tell binding control to which list of data
items to bind to?

As an example - I could create  data source class tableH, which
contains several Hashtable objects.What needs tableH to implement
( besides Hashtable objects ), so that we could tell GridView(via
DataMember) to which of hashtables to bind to? I would guess that
tableH needs a property which specifies the name of hashtable the
control should bind to, and when the time comes, GridView will check
this property and then bind to appropriate table. But what should the
name of that property be?

To create a custom "set of collections" class similar to DataSet-of-
DataTable, you need to implement IListSource interface on your DataSet-
like class, and return true from ContainsListCollection property of
that interface. From there it gets a bit messy - individual
collections within, together with their names, are represented with
PropertyDescriptors; so you might want to just look at C# code that
shows how exactly DataSource/DataMember combo is resolved, here:

http://victorsergienko.com/ilistsource-explained-howto/
I don’t understand what you mean. In the code below I initialized
member named “testBind” inside Page_Load(), right before calling
DataBind(), and “Label1” still managed to bind with testBind and
display its value:

 <asp:Label ID="Label1" Text='<%# testBind %>' ... />

    public partial class _Default : System.Web.UI.Page
    {
        public string testBind;
        private void Page_Load(object sender, EventArgs e)
        {
             testBind = “someWord”;
             this.DataBind();
        }

I do apologize - that is indeed the case for <%# %> markup - you can
use DataBind() to control when the assignment happens. What I said
before about PreInit was true for <%= %>, which is not affected by
data binding at all, and the values for it are calculated before
PreInit and Init.
Above code will perform data binding if I replace Text='<%#
testing.someWord %> with  Text='<%# WebApplication1.Testing.someWord
%>

-- Since Testing class is defined in same assembly and in same
namespace as _aspx class, I would assume runtime would be able to find
the Testing even if I don’t specify its fully qualified name?

Are you sure the _generated_ class for your aspx markup ends up in the
same namespace as your code-behind class from which it inherits?
Because I do not know if that is the case, and, given this example, am
inclined to think that it is not.

Keep in mind that all code in <% %> is executed in the context of that
generated class, _not_ your code-behind class. If you need to bring a
namespace into scope in an .aspx file, use the @Import directive.
You mean  simple types ( and structs in general ) are automatically
boxed when used in data binding expression? Why?

No. By "object" I don't mean "value of type System.Object", I merely
mean "value" as opposed to "variable". Since every value in .NET is of
type that is ultimately derived from System.Object, it is also correct
to say that every .NET value is an object. A local int variable is a
location that contains an int object, for example, even though no
boxing takes place.
 
F

frankswildyearstom

hello,


To create a custom "set of collections" class similar to DataSet-of-
DataTable, you need to implement IListSource interface on your DataSet-
like class, and return true from ContainsListCollection property of
that interface. From there it gets a bit messy - individual
collections within, together with their names, are represented with
PropertyDescriptors; so you might want to just look at C# code that
shows how exactly DataSource/DataMember combo is resolved, here:

http://victorsergienko.com/ilistsource-explained-howto/

I guess we can only use DataMember property when Control.DataSource
property is set, but not when Control.DataSourceID property is set?
I do apologize - that is indeed the case for <%# %> markup - you can
use DataBind() to control when the assignment happens. What I said
before about PreInit was true for <%= %>, which is not affected by
data binding at all, and the values for it are calculated before
PreInit and Init.

-- Just out of curiosity – when exactly does Asp.Net initialize server
controls with attribute values? Right after PreInit event?

-- I assume data source ( Testing class in our case) must already be
in existance at the time server controls ( Label1 in our case ) are
initialized with attribute values?

public class Testing
{
public static string someWord=”wildYears”;
}

<asp:Label ID="Label1" Text='<%# Testing.someWord %>' ... />




much appreciated
 
P

Pavel Minaev

I guess we can only use DataMember property when Control.DataSource
property is set, but not when Control.DataSourceID property is set?

As far as I know, DataSourceID is just a way to declaratively wire up
data sources and data bound controls. I don't see anything stopping
you from implementing a data source that is referenceable via
DataSourceID, and also supporting DataMember. I don't think any of the
stock ones do that, however.
-- Just out of curiosity – when exactly does Asp.Net initialize server
controls with attribute values? Right after PreInit event?

See http://msdn.microsoft.com/en-us/library/ms178472.aspx.
Specifically:

"Init - Raised after all controls have been initialized and any skin
settings have been applied. Use this event to read or initialize
control properties."
-- I assume data source ( Testing class in our case) must already be
in existance at the time server controls ( Label1 in our case ) are
initialized with attribute values?

public class Testing
{
       public static string someWord=”wildYears”;

}

<asp:Label ID="Label1"  Text='<%# Testing.someWord %>' ... />

In your case, since you're referencing a static member, it's always
"in existence". You may catch the moment when it's still null using
convoluted recursive static initialization code, but I don't think
that's something you need to worry about here.
 
F

frankswildyearstom

hello,


Seehttp://msdn.microsoft.com/en-us/library/ms178472.aspx.
Specifically:

"Init - Raised after all controls have been initialized and any skin
settings have been applied. Use this event to read or initialize
control properties."

I’ve read it. But it doesn’t say at what point Asp.Net first starts to
initialize the controls with attribute values. I thought that perhaps
the initialization of controls using attribute values spans over
multiple events
In your case, since you're referencing a static member, it's always
"in existence". You may catch the moment when it's still null using
convoluted recursive static initialization code, but I don't think
that's something you need to worry about here.


But if it wasn’t a static member, but instead an instance created
outside our web page class ( don’t know of any specific example ),
then it would have to be brought into “an existance” at Page.PreInit
at the latest?


thanx much
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top