|
thank you very much,Mr.Nick Parker.You gave me the correct link
|
|
|
|
|
|
Hi,
I am writing a forms based application, which has been working fine, until I moved my project to another computer with the same version of Visual studio. Now my initial form does not show up at all.
This is what I have done:
I have a console application that starts three forms, one after the other. Each form implements two methods invloved in starting the form in its own separate thread.
class UIForm : ....
{
Thread formThread = null;
public void OpenForm()
{
// formThread is a private member of the current form
formThread = new Thread( new ThreadStart( this.ShowForm ) );
formThread.Start();
}
private void ShowForm()
{
Application.Run( this );
}
.
.
.
}
The console application then starts the form like this:
UIForm theForm = new UIForm();
theForm.OpenForm();
This worked fine until I moved my project to another machine.
Any help, comments or advise is much appreciated!!
Thanks!
|
|
|
|
|
Given my limited understanding of all things .Net, take what I say with a grain of salt.
The thread that creates the window must be the one that updates the window. The thread that creates the window must also participate in a message loop. Although you may get away with violating these rules some of the time, it is guarenteed to bite you in the butt sometime in the future.
Unless you are doing something really special, I would have one thread handle all of the UI and have the other threads doing non-UI stuff. Use Form.Invoke() to handle communication between the threads.
|
|
|
|
|
I agree to what you say, but I don't see how I violate any of the rules in the startup phase. The form is started in its own thread, which should then be bound to the message loop. Or have I misunderstood things?
|
|
|
|
|
You created the window using one thread then executed another to make it visible. This violates the first principle I stated above.
Try creating the window with the new thread.
|
|
|
|
|
Thank you very much! I discovered your solution by trial and error, but I did not understand why. Now I now that there is something behind it. Again, thank you.
|
|
|
|
|
Hello, i'm having a problem getting an byte[] out of an arraylist...
I use an enumerator so the code is as followed:
bIpAdres = Convert.ToByte(ipsEnum.Current);
bIpAdres however is a byte[], and the values in the collection are also arrays, but writing
Convert.ToByte[]
doesn't work.
How should I do this?
Grtz, Bert
|
|
|
|
|
While the answer is in the documentation, the name should say enough: Convert.ToByte converts an argument to a single byte . Notice how it's singular?
If ipsEnum.Current represents a byte[] array, then simply cast it:
bIpAdres = (byte[])ipsEnum.Current;
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
So if I understand you correctly you have an ArrayList that contains a byte[] as elements. If so and you are confident that the ArrayList does in fact contain the values then the following will work.
foreach(byte[] arr in arrList)
{
//Do something
};
Alternatively,
foreach(object obj in arrList)
{
byte[] arr = (byte[])obj;
};
|
|
|
|
|
I've got a (managed)directX function i'm trying to call that takes a stream to an bitmap/image file or object, but i'd like to have the image file handled directly, rather than using a stream to a file.
But i'm wondering whether serialisation is the right way to go. Will this remove the image formatting? Is there a way to cast a Bitmap or Image into a byte[] structure?
I really should know this, but all this matrix maths and texture alignment has melted my brain
Cheers
Cata
|
|
|
|
|
Save the Bitmap to a MemoryStream , then call MemoryStream.ToArray to get a byte[] array.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Hello,
I run the program below to handle winmessages from an application written in a 4GL. If I close the 4GL window which uses this program, the C# program receives the WM_DESTROY message, but rebuilding the C# program after that fails because it is 'in use'. I suspect that I have to dispose some objects on WM_DESTROY? How can I code for that? I just started learning C#, if you can point me to some info about this I would be happy too.
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsApplication1
{
[ClassInterface(ClassInterfaceType.AutoDual)]
public class GenericWindow : NativeWindow
{
public const int WM_ERASEBKGND = 0x14;
public const int WM_DESTROY = 0x0002;
private const int GWL_WNDPROC = -4;
private const int WM_SYNCPAINT = 0x0088;
private const int WM_NCPAINT = 0x0085;
private const int WM_PAINT = 0x000F;
private IntPtr oldWndProc = IntPtr.Zero;
private Win32WndProc newWndProc = null;
private int hIcon;
#region Imported User32.DLL functions
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static public extern int GetDC(int hWnd);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int ReleaseDC(int hWnd,int hDc);
[DllImport("User32.dll")]
private static extern int DestroyIcon(int hIcon);
[DllImport("user32.dll")]
public static extern int DrawIcon(int hdc, int x,int y, int hIcon);
[DllImport("user32.dll", EntryPoint="CallWindowProc")]
private static extern int CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern int ExtractIcon(int hInst, string lpszExeFileName, int nIconIndex);
[DllImport("user32.dll")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, Win32WndProc newProc);
[DllImport("user32.dll")]
private static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
#endregion
// A delegate that matches Win32 WNDPROC:
private delegate int Win32WndProc(IntPtr hWnd, int Msg, int wParam, int lParam);
public GenericWindow()
{
}
public void NotifyWindow(int windowHandle)
{
this.AssignHandle((IntPtr)windowHandle);
oldWndProc = GetWindowLong((IntPtr)windowHandle,GWL_WNDPROC);
newWndProc = new Win32WndProc(MyWndProc);
SetWindowLong((IntPtr)windowHandle, GWL_WNDPROC,newWndProc);
PaintExtras();
}
private int MyWndProc(IntPtr hWnd, int Msg, int
wParam, int lParam)
{
int pHandle;
switch(Msg)
{
case WM_PAINT:
pHandle = CallWindowProc(oldWndProc, hWnd,Msg, wParam, lParam);
PaintExtras();
return pHandle;
case WM_DESTROY:
pHandle = CallWindowProc(oldWndProc, hWnd,Msg, wParam, lParam);
//MessageBox.Show("dest");
return pHandle;
default:
return CallWindowProc(oldWndProc, hWnd, Msg,
wParam, lParam);
}
}
public void PaintExtras()
{
int hdc = GetDC(this.Handle.ToInt32());
if (hdc != 0)
{
hIcon = ExtractIcon(this.Handle.ToInt32(),"C:\\progress10\\wrk\\experim\\down.ico",0);
int ret = DrawIcon (hdc, 1, 1, hIcon);
ret = DestroyIcon (hIcon);
ret = ReleaseDC(this.Handle.ToInt32(),hdc);
}
}
}
}
regards,
Stefan.
|
|
|
|
|
Why not just override NativeWindow.WndProc instead of defining your own window procedure? The WndProc services the same purpose - to subclass windows. You would call base.WndProc in your override to create the message chain.
You should call DestroyHandle when finished with the NativeWindow . To do this via the disposable pattern, you must implement the disposable pattern, which dictates when and what gets released. Native handles should always be released, and managed resources should be released only when the IDisposable.Dispose implementation is called. Simple, the disposable patter looks like this:
class MyClass : IDisposable
{
~MyClass()
{
Dispose(false);
}
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
}
} The NativeWindow class is used quite a bit in the BCL. I recommend using a disassembler (if you know how to read IL; if not, it's always a good idea to learn) like ildasm.exe that ships with the .NET Framework SDK, or a decompiler like .NET Reflector to see how it's used throughout the Framework Class Library.
[EDIT: Mistakenly typed "override" instead of "virtual". Fixed.]
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Thanks for your reaction. Maybe I do not understand your proposal to solve this problem, as said I am just a C# beginner. You can find my changed code hereunder. If I try to rebuild it I get compiler errors:
'WindowsApplication1.GenericWindow.Dispose(bool)': no suitable method found to override
The designer could not be shown for this file because none of the classes within it can be designed. The designer inspected the following classes in the file:
GenericWindow --- The base class 'System.Windows.Forms.NativeWindow' cannot be designed.
Any idea?
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsApplication1
{
[ClassInterface(ClassInterfaceType.AutoDual)]
public class GenericWindow : NativeWindow, IDisposable
{
private delegate Int32 EnumChildProc(IntPtr hWnd, IntPtr lParam);
private const int GWL_WNDPROC = -4;
private const int WM_PAINT = 0x000F;
private IntPtr oldWndProc = IntPtr.Zero;
private Win32WndProc newWndProc = null;
private int hIcon;
private int XPos;
private int YPos;
#region Imported User32.DLL functions
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static public extern int GetDC(int hWnd);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int ReleaseDC(int hWnd,int hDc);
[DllImport("User32.dll")]
private static extern int DestroyIcon(int hIcon);
[DllImport("user32.dll")]
public static extern int DrawIcon(int hdc, int x,int y, int hIcon);
[DllImport("user32.dll", EntryPoint="CallWindowProc")]
private static extern int CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern int ExtractIcon(int hInst, string lpszExeFileName, int nIconIndex);
[DllImport("user32.dll")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, Win32WndProc newProc);
[DllImport("user32.dll")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr newProc);
[DllImport("user32.dll")]
private static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
#endregion
// A delegate that matches Win32 WNDPROC:
private delegate int Win32WndProc(IntPtr hWnd, int Msg, int wParam, int lParam);
public GenericWindow()
{
}
~GenericWindow()
{ MessageBox.Show("destr");
Dispose(false);
}
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Dispose managed resources
}
// Dispose unmanaged resources. Ex: NativeWindow.DestroyHandle
this.DestroyHandle();
}
public void NotifyWindow(int windowHandle)
{
this.AssignHandle((IntPtr)windowHandle);
oldWndProc = GetWindowLong((IntPtr)windowHandle,GWL_WNDPROC);
newWndProc = new Win32WndProc(MyWndProc);
SetWindowLong((IntPtr)windowHandle, GWL_WNDPROC,newWndProc);
PaintExtras(1,1);
}
private int MyWndProc(IntPtr hWnd, int Msg, int
wParam, int lParam)
{
int pHandle;
switch(Msg)
{
case WM_PAINT:
pHandle = CallWindowProc(oldWndProc, hWnd,Msg, wParam, lParam);
PaintExtras(XPos, YPos);
return pHandle;
default:
return CallWindowProc(oldWndProc, hWnd, Msg, wParam, lParam);
}
}
private void PaintExtras(int xPos, int yPos)
{
XPos = xPos;
YPos = yPos;
int hdc = GetDC(this.Handle.ToInt32());
if (hdc != 0)
{
hIcon = ExtractIcon(this.Handle.ToInt32(),"C:\\progress10\\wrk\\experim\\down.ico",0);
int ret = DrawIcon (hdc, xPos, yPos, hIcon);
ret = DestroyIcon (hIcon);
ret = ReleaseDC(this.Handle.ToInt32(),hdc);
}
}
}
}
regards,
Stefan.
|
|
|
|
|
I'm sorry - that should be "virtual" not "override". I get so used to typing the latter.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Thank you. The code compiles now, but I still get errors stating that files are in use on rebuilding after I closed the 4GL window. With spy++ I see as last received messages WM_ESTROY and WM_NCDESTROY.
I placed a debugging message in de decontructor ~GenericWindow(), it does not show up after the closingaction. Calling Dispose() from within my 4GL does not help either. Any idea how to get this working?
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsApplication1
{
[ClassInterface(ClassInterfaceType.AutoDual)]
public class GenericWindow : NativeWindow, IDisposable
{
private delegate Int32 EnumChildProc(IntPtr hWnd, IntPtr lParam);
private const int GWL_WNDPROC = -4;
private const int WM_PAINT = 0x000F;
private IntPtr oldWndProc = IntPtr.Zero;
private Win32WndProc newWndProc = null;
private int hIcon;
private int XPos;
private int YPos;
#region Imported User32.DLL functions
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static public extern int GetDC(int hWnd);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int ReleaseDC(int hWnd,int hDc);
[DllImport("User32.dll")]
private static extern int DestroyIcon(int hIcon);
[DllImport("user32.dll")]
public static extern int DrawIcon(int hdc, int x,int y, int hIcon);
[DllImport("user32.dll", EntryPoint="CallWindowProc")]
private static extern int CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern int ExtractIcon(int hInst, string lpszExeFileName, int nIconIndex);
[DllImport("user32.dll")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, Win32WndProc newProc);
[DllImport("user32.dll")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr newProc);
[DllImport("user32.dll")]
private static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
#endregion
// A delegate that matches Win32 WNDPROC:
private delegate int Win32WndProc(IntPtr hWnd, int Msg, int wParam, int lParam);
public GenericWindow()
{
}
~GenericWindow()
{ MessageBox.Show("destr");
Dispose(false);
}
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Dispose managed resources
}
// Dispose unmanaged resources. Ex: NativeWindow.DestroyHandle
this.DestroyHandle();
}
public void NotifyWindow(int windowHandle)
{
this.AssignHandle((IntPtr)windowHandle);
oldWndProc = GetWindowLong((IntPtr)windowHandle,GWL_WNDPROC);
newWndProc = new Win32WndProc(MyWndProc);
SetWindowLong((IntPtr)windowHandle, GWL_WNDPROC,newWndProc);
PaintExtras(1,1);
}
private int MyWndProc(IntPtr hWnd, int Msg, int
wParam, int lParam)
{
int pHandle;
switch(Msg)
{
case WM_PAINT:
pHandle = CallWindowProc(oldWndProc, hWnd,Msg, wParam, lParam);
PaintExtras(XPos, YPos);
return pHandle;
default:
return CallWindowProc(oldWndProc, hWnd, Msg, wParam, lParam);
}
}
public void setPos(int xPos, int yPos)
{
XPos = xPos;
YPos = yPos;
}
private void PaintExtras(int xPos, int yPos)
{
XPos = xPos;
YPos = yPos;
int hdc = GetDC(this.Handle.ToInt32());
if (hdc != 0)
{
hIcon = ExtractIcon(this.Handle.ToInt32(),"C:\\progress10\\wrk\\experim\\down.ico",0);
int ret = DrawIcon (hdc, xPos, yPos, hIcon);
ret = DestroyIcon (hIcon);
ret = ReleaseDC(this.Handle.ToInt32(),hdc);
}
}
}
}
regards,
Stefan.
|
|
|
|
|
Something else I noticed right off the bat:
[ClassInterface(ClassInterfaceType.AutoDual)] NEVER use this. Auto-generated class interfaces are the worst thing ever added to the Framework, in my opinion. If you know anything about COM, you should agree. While .NET isn't prone to problems caused my moving members around, native code (like the COM infrastructure) is. Always declare your class interfaces explicitly, always use a hard-coded, unchanging guid via the GuidAttribute on both your class and COM-exposed interfaces, and never change published interfaces. Derive new ones, implement those as the first interface of your class (which the CLR treats as your class interface when you use ClassInterfaceType.None with the ClassInterfaceAttribute ) successively when releasing new interfaces. This is how you'd do it in COM and need to replicate that behavior in .NET. While .NET doesn't care, COM sees a different story and clients will start breaking left and right. That is not the problem at hand, however.
If you are exposing this to COM and using your class, the make sure you're releasing the object by calling IUnknown::Release in your native code. If not, the DLL is not unloaded and will be in use (soft-locked).
And once again, you should not sub-class the Window how you're currently doing it. This is most likely causing the problem. Simply override WndProc (just like you'd do on any other Windows Forms control (since most encapsulates native Common Controls) when a particular message isn't handled in a .NET-friendly manner. Catch the WM_PAINT message like in the following and handle that however is necessary:
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PAINT)
{
}
base.WndProc(ref m);
} I very much doubt the Framework is expecting you to sub-class the Windows by re-assigning its window procedure. Just don't. You're performing extra work - and putting extra work on the CPU for marshaling - when it's not necessary. The window procedure is already encapsulated and exposed for you: NativeWindow.WndProc .
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Thanks a lot for your extensive explication. I will google around in the coming time to get some code to make the release-call (and the rest) work, and look for some extra info on using com.
I hope I can get back to you if I do not (fully) succeed.
regards,
Stefan.
|
|
|
|
|
I have a dataTable tbl. If my app. start it's emty. I can fill it manually but i can also save the table of the last session. I do that with XmlWrite().
To load the table i use the XmlRead() method. After I done this tbl_ColumnChanged stops raising events although my Comlumns are changing.
I'm debugging for a while to find out the raison why it stops raising event but it has not been very succesfull till now. Can someone tell me why?
Dogan
|
|
|
|
|
i've a problem with the code below on how i've used the structure,binary files and some of the functions!
the code:
/* bus reservation system*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXSEAT 45
#define FILE1 fptr1;
#define FILE2 fptr2;
struct info {
char name[15];
char date[8];
char dest[15];
int seat;
float amount;
char mark;
};struct info record;
void ticket();
void sold_seat();
void reservation();
void thank_u();
void bus_fare();
void bus_report();
void check_it();
int q,rseat;
main()
{
int op;
START:printf("1:MAKE RESERVATION\n");
printf("2:SELL A TICKET\n");
printf("3:EXIT\n");
printf("enter your choice:\n");
scanf("%d",&op);
switch(op)
{case 1:{reservation();}
break;
case 2:{ticket();}
break;
case 3:exit(0);
break;
default:{printf("\nenter listed choice!\n");
goto START;
break; }}
return 0;
}
void reservation()
{
FILE*fptr1,*fptr2;
char name[15],date[15],dest[15],bname[15];
int i,seat;
fptr1=fopen("bus.txt","rb");
fptr2=fopen("user.txt","wb");
while(!feof(fptr1))
printf("\nenter bus name:\n");
scanf("%s",bname);
fptr1=fopen("bus.txt","rb");
if (fptr1==NULL)
printf("\nenter name:\n");
scanf("%s",(record).name);
printf("\nenter your destination:\n");
scanf("%s",(record).dest);
printf("\ndate:\n");
scanf("%s",(record).date);
check_it();
fptr2=fopen("user.txt","rb+");
fscanf(fptr1,"%s%d",(record).name,&seat);
fclose(fptr1);
fclose(fptr2); thank_u();
}
void check_it()
{
FILE*fptr2;
int seat,rseat,pseat,n;
fptr2=fopen("user.txt","rb");
n=0;
while(!feof(fptr2))
{START: printf("enter seat no:\n");
scanf("%d",&seat);
if(seat==seat)
{printf("seat taken\n""pick another seat\n");
goto START; }
else
{scanf("%d",&seat);}
rseat=n+1;
pseat=MAXSEAT-rseat;
if(n=MAXSEAT)
{printf("bus full");
reservation();}
n++;}
fclose(fptr2);
}
void ticket()
{
FILE*fptr1;
char mark,name[15],bname[15];
int seat;
fptr1=fopen("bus.txt","rb");
printf("enter bus name:\n");
scanf("%s",bname);
while(!feof(fptr1))
if (fptr1=fopen("bus.txt","rb+")==NULL)
{reservation();
fclose(fptr1);}
else
{printf("enter name:\n");
scanf("%s",name);
printf("enter seat no:");
scanf("%d",&seat);
if(strcmp((record).name,name)&&(record.seat,seat)==0)
{{printf("seat paid??(Y/N)\n");
scanf("%c",mark);}
if(mark='Y' || 'y')
{bus_fare();} }
else
{printf("\nthe seat is reserved!\n");}
}fclose(fptr1); thank_u();
}
void thank_u()
{
printf("\n***THANK YOU***\n");
}
void bus_fare()
{
float amount,sum;
sold_seat();
printf("\nenter amount paid:\n");
scanf("%f",&amount);
sum=q*amount;
printf("\ntotal revenue:%f\n",sum);
}
void bus_report()
{
check_it();
sold_seat();
bus_fare();
}
void sold_seat()
{
int q,i;
char mark;
q=0;
for(i=1;i<=45;i++)
if(mark=='Y'||'y')
{q=q+1;
printf("\nseats reserved and tickets sold:%d\n",q);}
check_it();
printf("\nseats reserved and tickets not sold:%d\n",rseat-q);
printf("\nseats not reserved:\n",MAXSEAT-rseat);
}
project was:
In this project you will develop a program that can be used by a bus company to
manage reservations of potential travellers to the buses operated by the company.
When invoked the program should present the user with two choices and let user
choose by inputting corresponding number:
1.Make a reservation
2.Sell a ticket.
If user choose (1) the program should,
1.Prompt user to input Bus name and find the file with that name, if not found create
a binary file with given name for keeping reservations for that bus.
2.Create a structure with all information needed to record a reservation.
3.Check for consistency that the seat is not taken already and the bus is not full.
4.Write the reservation into the binary file for chosen bus maintaining consistency.
5.Thank the user and exit.
If user choose (2) the program should,
1.Ask the user to input the name of bus in which reservation was previously made.
2.If the bus file does not exist, inform the user of the problem and repeat step 1.
3.Ask user input name and seat number reserved
4.If name and seat number are correct, mark the seat as sold and record amount of
money paid for the seat.
5.Finally the program should thank the user for using the program and display a
pretty report showing the current status of chosen bus in terms of which seats are
reserved, which ones for which the ticket is sold and total revenue collected so far.
thanks.
|
|
|
|
|
505 wrote:
i've a problem with the code below on how i've used the structure,binary files and some of the functions!
What would the problem be? You cannot just say "I've a problem..." and expect people to know what it is. Heck! We don't even know what your code is supposed to do - And no, we are not going to trawl through the code to figure out what it is supposed to do.
Next, this code appears to be C++. You should post it in a C++ forum. This forum is for C#. You will have a better chance of someone helping you if you post your question in the correct forum.
Do you want to know more?
WDevs.com - Member's Software Directories, Blogs, FTP, Mail and Forums
|
|
|
|
|
Hi All,
I've already sent this problem and was replied by some senior software engineer of microsoft but I could not be clarified. Let me elaborate the problem again:
I've populated a dataset object with records from multiple tables by executing a stored procedure(in which I've used the joining of the tables). Then I bound a datagrid with this dataset. When user made the changes, is there any way that these changes can be accomodated in the original database tables(because there are more than one tables hence I feel problem in propagating these changes). Can anyone plz suggest me some solution or the way with which this can be dealt with?
I shall be very thankful
Regards
|
|
|
|
|
The CommandBuilder will not be able to generate the INSERT, DELETE and UPDATE commands of a multiple table query. U will have to do this manually.
The best way is to create parametrized commands:
As an example, imagine we have the following query: "SELECT T1.A,T1.B, T1.C, T2.D FROM T1,T2 WHERE T2.C=T1.C" being T1.A the primary key of table T1.
We create a dataadapter and fill up our DataSet:
myDataAdapter.Fill(myDataSet,"myTable")
For sake of simplicity, let us say that ur datagrid is bound to the table resulting of this query and shows fields A,B, C and D, but only A, B and C can be edited->thus we only have to propagate changes back to table T1. (Propagating to T2 wouldnt be a problem, but lets keep this as short as posible).
We would create our update, delete and insert commands as follows:
INSERT COMMAND: INSERT INTO T1(A,B,C) VALUES(@A,@B,@C)
Parameters would be mapped to DataColumns A,B and C and RowVersion would be Current.
DELETE COMMAND: DELETE FROM T1 WHERE T1.A=@A
Parameter would be mapped to DataColumn A and RowVersion would be Original.
UPDATE COMMAND: UPDATE T1 SET T1.A=@A_current, T1.B=@B, T1.C=@C WHERE T1.A=@A_original
Parameters would be mapped to DataColumns A,B,C and versions would be Current except the primarykey used in the Where statement which sould be Original.
Once created all commands, we would assign them to our dataadapter and to propagate changes back to the database we would execute:
myAdapter.Update(myDataSet,"myTable");
If your datagrid does not contain all the fields of ur table then pass along the default values in ur sql commands (no need of parameters in those cases).
U could also solve the problem using the dataTable.GetChanges([rowVersion]) method and iterating through all the modified rows and executing the necessary NonQueryCommands using the Update/Insert or Delete commands similar to the shown above depending on the RowState of the current row. This would be a better solution when propagating changes back to multiple tables as you would only have to iterate once throug ur modified rows in order to propagate changes to all afected tables (just run all the nonqueries to all the tables u need on each row).
|
|
|
|
|
|