|
Hi everyone, I am fairly new to C# (2 months) and I need some serious help.
I need to populate a RadioButtonList (id=rbl) with the first set of data (QUESTIONID = 1) from a XML data (sports.xml).
I am having a hard time setting the DataTextField = "CHOICETEXT" and DataValueField = "CHOICEID".
I am not even sure if this is the best xml format either.
The code below the xml will cause an error. "System.Data.DataRowView' does not contain a property with the name CHOICETEXT"
Please help me to solve this problem. Thank you in advance.
<TEST>
<QUESTION>
<QUESTIONID> 1 </QUESTIONID>
<TYPE>radio</TYPE>
<TEXT>Who is the going to win the NCAA?</TEXT>
<CHOICES>
<CHOICE>
<CHOICEID> 1 </CHOICEID>
<CHOICETEXT>UAB</CHOICETEXT>
</CHOICE>
<CHOICE>
<CHOICEID> 2 </CHOICEID>
<CHOICETEXT>Kansas</CHOICETEXT>
</CHOICE>
</CHOICES>
<ANSWER> 1 </ANSWER>
<RESPONSE>
<CORRECT>You got that right baby!.</CORRECT>
<WRONG>ARE YOU CRAZY?</WRONG>
</RESPONSE>
</QUESTION>
<QUESTION>
<QUESTIONID> 2 </QUESTIONID>
<TYPE>radio</TYPE>
<TEXT>Who is going to win the Stanley Cup?</TEXT>
<CHOICES>
<CHOICE>
<CHOICEID> 1 </CHOICEID>
<CHOICETEXT>Red Wings</CHOICETEXT>
</CHOICE>
<CHOICE>
<CHOICEID> 3 </CHOICEID>
<CHOICETEXT>Maple Leafs</CHOICETEXT>
</CHOICE>
</CHOICES>
<ANSWER> 2 </ANSWER>
<RESPONSE>
<CORRECT>You got that right baby!.</CORRECT>
<WRONG>ARE YOU CRAZY?</WRONG>
</RESPONSE>
</QUESTION>
</TEST>
DataSet ds = new DataSet();
ds.ReadXml(MapPath("sports.xml"));
DataView dv = new DataView(ds.Tables["QUESTION"]);
dv.RowFilter = "QUESTIONID = 1";
rbl.DataSource = dv;
rbl.DataTextField = "CHOICETEXT";
rbl.DataValueField = "CHOICEID";
rbl.DataBind();
|
|
|
|
|
Because the DataRowView over that table wouldn't have those fields directly under its scope. In relation to the QUESTION scope, they would be CHOICES/CHOICE/CHOICETEXT and CHOICES/CHOICE/CHOICEID. Use these strings as your DataTextField and DataValueField except replace "/" with ".". This notation is supported in Windows Forms bindings, so it may just work here (things work a little differently).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Hello Heath,
Thank you for your reply. I tried your suggestion and got
"DataBinder.Eval: 'System.Data.DataRowView' does not contain a property with the name CHOICES.CHOICE.CHOICETEXT"
any other suggestions?
|
|
|
|
|
Not really. It's documented that it should work and IIRC I've done something similar before with success, except that I've never bound to a DataView and instead bound to a DataSet with DataGrid.DataMember set to the DataTable name I needed. I know this won't give you the filter you want, but you could try it to see if it works that way. Other than that, I'd recommend just reading about all the relevant properties like DataGrid.DataSource and DataGrid.DataMember , along with other related properties. There's a lot of information and examples buried in there.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Hey all
For an example, lets say I want to pass 3 bstr's to an unmanged dll (using C#) and one is to be passed by reference because that will hold the output of the function call. So here's what I do (please ignore sytax):
Import the function:
[DllImport("mydll.dll")]<br />
void MyFunc( [MarshalAs(UnmanagedType.BStr)] string A, [MarshalAs(UnmanagedType.BStr)] string B, [MarshalAs(UnmanagedType.BStr)] ref string C);
Now, I use that function:
string output = "";<br />
MyFunc("test", "another", ref output);
Great, it works no prob, although, 'output' never changes. This is due to the fact that string isn't immutable, no biggy, I'll try the StringBuilder class in place of that string, so I have:
Import the function:
[DllImport("mydll.dll")]<br />
void MyFunc( [MarshalAs(UnmanagedType.BStr)] string A, [MarshalAs(UnmanagedType.BStr)] string B, [MarshalAs(UnmanagedType.BStr)] ref System.Text.StringBuilder C);
Now, I use that function:
System.Text.StringBuilder output = new System.Text.StringBuilder("");<br />
MyFunc("test", "another", ref output);
This failes with the following exception:
An unhandled exception of type 'System.Runtime.InteropServices.MarshalDirectiveException' occurred in winp2p.dll
Additional information: Can not marshal parameter #4: Invalid managed/unmanaged type combination (StringBuilders must be paired with LPStr, LPWStr, or LPTStr).
Now this makes sence since I'm trying to pass a BStr by reference, but I cannot find out how! Help please!!
Jason
|
|
|
|
|
Any particular reason why your using BStr's? BSTR's were native to VB6, not anything.NET...
Is your .DLL written to handle them?
RageInTheMachine9532
|
|
|
|
|
The dll i'm importing is the reason...
They are actually of type PWSTR, which, I read somewhere, is of type BSTR, so, when I use MarshalAs I can use UnmanagedType.BStr....
lets say the actual dll prototypes look like:
void myfunc(pcwstr a, pcwstr b, ppwstr c);
where ppwstr is just pwstr*
I need to be abel to pass 'c' in by reference so I can obtain my output.
|
|
|
|
|
schnee2k3 wrote:
They are actually of type PWSTR, which, I read somewhere, is of type BSTR,
Not quite. BSTR's begin with a 32-bit byte length preceding the array of Unicode characters. The length is in BYTES, not characters. You'd probably be better off Marshaling them as LPWSTR's. All PWSTR means is "Pointer to Wide (or Unicode) String". Kind of odd though, it's usually called LPWSTR (Long Pointer... Unless your actually using BSTR's in your app or .DLL, you'd be better off not using them.
Now, the reason why your string you passed by ref didn't change is because it had a zero length to start with. Managed strings are immutable, they can't change unless poked into directly. Unless your .DLL will deallocate and allocate you a new Managed string, you have to declare the string at a maximum size you can handle first. Something like either a character array of zero's to satisfy the termination character at the end of a string, or use Stringbuilder to do it. But even with StringBuilder, you have to tell it to allocate enough space to handle the maximum size string you expect to get back.
RageInTheMachine9532
|
|
|
|
|
So, here is what I did:
Importing the function:
<br />
[DllImport("mydll.dll")]<br />
public static extern void MyFunc([MarshalAs(UnmanagedType.BStr)] string A, <br />
[MarshalAs(UnmanagedType.BStr)] string B, <br />
[MarshalAs(UnmanagedType.LPWStr)] ref System.Text.StringBuilder C);<br />
The actual call:
<br />
System.Text.StringBuilder dataOut= new System.Text.StringBuilder(1024);<br />
<br />
MyFunc(someString, anotherString, ref dataOut);<br />
This doesn't work because the pwstr is not the same as an lpwstr. I can verify that the dll is using A and B correctly as BStr's. I get an unhandled exception:
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in winp2p.dll
Additional information: Capacity exceeds maximum capacity.
I know for a fact also, that 1024 is WAY more than enough to hold what I need. I think this is happening because, I believe, that a PWSTR is not necasariy null terminated??
Anyways, the following code DOES work, although I HATE that it's in an unsafe block:
Importing the function:
<br />
[DllImport("mydll.dll")]<br />
public static extern void MyFunc([MarshalAs(UnmanagedType.BStr)] string A, <br />
[MarshalAs(UnmanagedType.BStr)] string B, <br />
ref IntPtr C);<br />
The actual call:
<br />
IntPtr dataOut = Marshal.AllocCoTaskMem(1024);<br />
string foo;<br />
<br />
unsafe<br />
{<br />
MyFunc(someString, anotherString, ref dataOut);<br />
foo = new string((char*)dataOut.ToPointer());<br />
}<br />
<br />
Marshal.FreeCoTaskMem(dataOut);<br />
In the above example, I do, in fact, get the string I am looking to get, BUT I really really really hate the unsafe block....
|
|
|
|
|
Dave's right - just use UnmanagedType.LPWStr - except the reason it's not working is because you're <cod>ref'ing your string. A string is already a reference type, so what you're doing is actually more like LPWSTR* , or a pointer to a pointer to a wchar_t . Don't use ref or out with reference types unless you need double-pointers (it happens).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Heath-
Here's the new code with your suggestions:
Importing the function:
[DllImport("mydll.dll")]<br />
public static extern void MyFunc([MarshalAs(UnmanagedType.BStr)] string A, <br />
[MarshalAs(UnmanagedType.BStr)] string B, <br />
[MarshalAs(UnmanagedType.LPWStr)] System.Text.StringBuilder C);
The actual call:
System.Text.StringBuilder dataOut= new System.Text.StringBuilder(1024);<br />
<br />
MyFunc(someString, anotherString, dataOut);<br />
<br />
string dataOutAsString = dataOut.ToString()
dataOutAsString contains 2 unkown characters (the boxes in debug). This is not anything close to what it should be returning. Removing [MarshalAs(UnmanagedType.LPWStr)] from the import does nothing, still just the 2 unkown characters.
Jason
|
|
|
|
|
Without seeing the garbage in a debugger, it would appear that the function you called filled in ASCII characters (8-bit), instead of the 16-bit Unicode characters that StringBuilder is looking for.
One clue would be how long is the string compared to the length you expect. Is it just about half as long?
Another would be to look at the values in the chars[] array in the StringBuilder. Parse out the values for high and low bytes and check them against the ASCII table to see if your actually getting two 8-bit characters crammed into a single 16-bit character field.
RageInTheMachine9532
|
|
|
|
|
That is what I was thinking as well, but it's only 2 characters long and the string I'm looking to return is around ~100 characters long....I am almost certain that the dll I'm using works soley with unicode characters. And also, isn't a char in .NET 16-bit? So my cast from the IntPtr to a string using a cast as char* would show that the dll is using unicode characters...correct? The integer value of position 0 is 8496 and of position 1 is 1937 in the string contained in StringBuilder. The 8496 correspoond to ascii characters 33 (!) and 48 (0), which are not valid for what I'm looking to get back.
Edit: Some further testing. Ran it multiple times, and same values come out, the string I am looking for is different each time (it's a like creating a new guid).
Jason
|
|
|
|
|
I am right about ref and out , trust me. Interop is something I've studied more in-depth than anything with .NET, and I study everything pretty deeply.
Anyway, I didn't look over the whole thing initially since Dave was helping you.
Following the messages below this one, you're right that chars in .NET are natively 16-bits, but they can be marshalled as 8-bit chars as well depending on the MarshalAsAttribute , or the StructLayoutAttribute and the DllImportAttribute (using the CharSet property for each) if you don't specify the MarshalAsAttribute (not always a need to).
So you're not really changing what a char is in managed code, but you're changing how its marshalled to and from unmanaged code.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
After reviewing the whole thread, I think I found your problem.
First, a "string is just an array of chars, so char* or char[] (for which a reference references the first element and is typically null-terminated, except for VB which sucks).
So, a PPWSTR is actually a char** , which is not only unnecessary in most cases, but probably incorrect. Also, Dave is right below (man, it feels weird saying that because my CEO who tries to program is named "Dave" and he's always wrong) - BSTR s and LPWSTR s (PWSTR , too) are not the same but can be. Here it's better to assume they won't be and just use UnmanagedType.LPWStr .
So, if your native function is declared as:
void myfunc(PWSTR a, PWSTR b, PWSTR c); ...your P/Invoked declaration should look like:
[DllImport("whatever.dll", CharSet=CharSet.Unicode)]
private static extern void MyFunc(string a, string b, string c); If one of those is meant to be an [out] param, you can use the OutAttribute but do not use out or ref for a reference type except in rare circumstances where you would have something like PPWSTR .
As I explained above, strings are already reference types. Very rarely do you use ref or out with reference types (interfaces, strings, etc.). There are types, though. QueryInterface , for example, uses LPVOID* , which is void** , so that's one place you'd need it (although there's no reason since the Marshal class already encapsulates this - but it's just an example off the top of my head).
Hope this helps.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
I completely understand what you are saying. Here is the problem, my function is declared as such:
void myfunc(PWSTR a, PWSTR b, PWSTR* c);
c will be a pointer to the PWSTR created by the function....
What is the best way to handle this?
|
|
|
|
|
If you can't change it (because you really doing need a PWSTR* to get the output), declare your method like so:
[DllImport("whatever.dll", CharSet=CharSet.Unicode)]
private static extern void myfunc(string a, string b, out string c);
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Please have my children.....i love you
Thanks so much for you help!
Just to clear something up, what's the difference between declaring ref and declaring out?
|
|
|
|
|
The difference between the two if that a ref parameter must be initialized to something before it is passed into the function being called. Out parameters don't need to be initialized.
Make sense? If not, think of an Array being passed into a function. Do you want/need to initialize the array, like defining it's dimensions and types, before you pass its pointer to the function or do you want the function to create the array for you?
RageInTheMachine9532
|
|
|
|
|
i have a question ...
could you translate this vb code to c# ? i tried it, but i failed ...
Private Sub Command1_Click()
Dim x As Integer
Dim var1 As Integer
Dim var2 As Integer
List1.Clear
x = Val(Text1.Text)
varX = Int(x / 3) + 1
var1 = 1
var2 = 1
var3 = 1
Do While Not var1 = x
tel = tel + 1
getal1 = var1
var2 = var2 + 1
getal2 = var2
getal3 = Val(x) - Val(getal1) - Val(getal2)
If getal1 <> getal2 And getal1 <> getal3 And getal2 <> getal3 And getal2 < getal3 Then
List1.AddItem getal1 & " + " & getal2 & " + " & getal3
Else
var1 = var1 + 1
var2 = var1
If tel = var3 + 1 Then Exit Do
var3 = tel
End If
Loop
End Sub
I'm making a program that when you enter a number, returns all the possibility's of how to make that number
example: ENTER : 14 Returned items = 1+2+11 = 14
1+3+10 = 14
1+4+9 = 14
1+5+8 = 14
1+6+7 = 14
2+3+9 = 14
2+4+8 = 14 ....
and you can't use the same number twice
... or the same combinations ex. 14 = 1 + 2 + 11 but not 2 + 1 + 11
i really hope somebody can help me !!!!
|
|
|
|
|
What have you produced in C#?
How have you failed?
Perl combines all the worst aspects of C and Lisp: a billion different sublanguages in one monolithic executable. It combines the power of C with the readability of PostScript. -- Jamie Zawinski
|
|
|
|
|
First off, let me say that you need to register the click event. So, before I convert this big block, let me know if you've done this. If you're using VS.NET and you double-click on the button in the designer, it should be taken care of for you. Let me know.
Michael Flanakin
Web Log
|
|
|
|
|
i registered the click event ...
and i'm using VS.Net ...
|
|
|
|
|
What's the error you got? There are a lot of unknowns in this method. It's hard to tell if something is supposed to be a local var or a class property. You would probably be better off posting the C# line that has the problem.
Michael Flanakin
Web Log
|
|
|
|
|
I may be wrong, but this smacks of someone asking for help on a homework assignment...
|
|
|
|
|