|
First, you should just grab all the data you need into the DataSet , including the master and detail tables. Unless this is an extremely huge DataSet , often-accessed data is better to pull down in one shot.
Then, take a look at a previous thread I posted a solution to in this forum: http://www.codeproject.com/script/comments/forums.asp?msg=665954&forumid=1649&XtraIDs=1649&searchkw=DataGrid&sd=10%2F1%2F2003&ed=11%2F25%2F2003#xx665954xx[^]
Basically, if you bind your master DataGrid.DataSource property to the DataSet and specify the appropriate table in the DataGrid.DataMember property, and then set the detail's DataGrid.DataSource to be the relationship between the two tables (implying that you create a strongly-typed DataSet and form a named relationship between the two DataTable s, which is really easy using the DataSet designer), clicking on a row in the master DataGrid will automatically filter the detail DataGrid with the related child rows. This way, no fetching is required.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
Thank you for your quick answer,
I know that the way you are showing in the reply is the preffered way, but I don't trust microsoft in the realisation on the data bindings and I'm just not comfortable with the datagrid control, except for viewing readonly data.
Any way this is a realy huge database (e.g. master table has about 16,000,000 and the detail is about 31 milion record) and I can't put this in a dataset.
So I must stick with this way of retrieving data.
Do you know any particular reason why is setting the datasource of a datagrid so slow. I'm thinking of creating my own control that will display the data (substitute for datagrid).
Dejan Mitev
|
|
|
|
|
The DataGrid does work and we use it a lot in our commercial application. Mostly likely, you're having such problem because the DataGrid loads all records instead of creating a virtual buffer in which to load records as they become visible. You might be better off with a third-part control. There are many out there, just google for them.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
Hi,
at the moment I'm developing an application, which extensively uses the FileSystemWatcher.
The received events are used by a logic component, which then calls a Third Party API in an appropriate case.
The Third Party is COM based, and is STA Threaded. (I recognized that, after switching on a Stress Test, crashing the whole system...).
For I was a Java Programmer in my former life, I don't have the .Net -KnowHow for to savely implement Mulit-Threading/Synchronisation matters.
(Don't want to crash again)
Important is for this Synch is:
- There mustn't be a timeout. Each Event must be processed!
Are there internal queuing mechanisms (which could overflow?)
What would be the best way?
I saw FileSystemWatcher has a SynchronisationObject Property.
How To handle that?
What delegate to invoke with what args there?
Doesn't that correspond to the FileSystemEventHandler?
I don't understand the Concept behind this Sync...
A Sample would help... thanks in adance!
|
|
|
|
|
Since you're new to .NET, read through all the classes in the System.Threading namespace. You'll find all your answers in there.
The important thing about your solution is that the FileSystemWatcher fires events synchronously. To handle the code in different threads, you have a variety of options. One is to use the ThreadPool , which has a method called QueueUserWorkItem . This creates a worker thread in a thread pool (so that your thread count doesn't skyrocket and monopolize the system resources) and even allows you to pass a state object (which could be a single object, an array, collection, list, etc.) unlike the Thread class (which works better for unit operations in a class that invoked it so it can access - in a synchronized manner if applicable - the class's resources).
The other way is to use delegates with asynchronous invocation (the BeginInvoke that the C# compiler (and some others) automatically generates, which means if you create your own delegate you won't see the BeginInvoke method in your IntelliSense drop-down list, but just type it correctly anyway).
So, to use a ThreadPool (and keep in mind this is very simplistic sample code, so read-up on what I'm talking about before copying and pasting this code), you could so something like the following:
private void myFileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DoFileDiff), e.FullPath);
}
private void DoFileDiff(object state)
{
string path = state as string;
int changedLines = Diff(path);
lock (this)
WriteToLog(path, "Changed", changedLines);
} Again, keep in mind I'm pulling stuff out of my head as only an example. Pay attention to the lock keyword, though. This resolves to a Monitor , which is in the namespace I mentioned at the beginning. You could also one of the various WaitHandle classes with a little more control over what gets locked and what doesn't, and what thread (in an MTA) has to wait for what other threads (note, too, that Thread.Join is available still with any of these methods I'm mentioning.
Using delegates with asynchronous execution doesn't give you the control you have with the ThreadPool , but if your code is quick it might be worth not using the ThreadPool . You should still reserve using the Thread class for simple cases, since you can't pass state objects to them. The following example will use the same DoFileDiff method as above for brevity:
private void myFileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
WaitCallback callback = new WaitCallback(DoFileDiff);
callback.BeginInvoke(e.FullPath, null, null);
} See the Asynchronous Programming Overview[^] topic in the .NET Developer's Guide in the MSDN Library for more information.
Again, any of the WaitHandle classes or the Monitor will work good to synchronize resources. If you do use the Monitor directly instead of the lock keyword, here's what the lock keyword resolves to so you should do something similar:
Monitor.Enter(syncRoot);
try
{
}
finally
{
Monitor.Exit();
}
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
Thanks a lot for your reply... that helps
Imagine the following Testcase:
Goal: The FileEventHandler process EACH event synchronously.
The Test app moves files in and out the watched folder (doforever until I say stop)
Fact is: At the moment, I have a monitor, lock or mutex or whatever for Sync. But if the process needs some time (I simulated this with Thread.Sleep(500) in my code [see below, just using extremes for testing])
the Events get lost, due to timeout(?).
How to handle that issue? The only thing I see is a MessageQueue, which I assume is Thread Safe (am I right?)
Is there a way configuring the FileSysWatcher in a way that these events wont get lost?
private AutoResetEvent ChangedEvent = new AutoResetEvent(true);
Boolean bEventLockAcquired = true;
try
{
Monitor.Enter(ChangedEvent);
bEventLockAcquired = ChangedEvent.WaitOne(0, false);
if (bEventLockAcquired)
{
switch (e.ChangeType)
}
case(WatcherChangeTypes.Created):
Console.WriteLine(e.Name + " " + e.ChangeType +
" Count " + i.ToString());
Thread.Sleep(500);
break;
case(WatcherChangeTypes.Deleted):
Console.WriteLine(e.Name + " " + e.ChangeType);
break;
}
i++;
}
}
catch(Exception ex)
{
log.Error("Error",ex);
}
finally
{
if (bEventLockAcquired)
{
ChangedEvent.Set();
}
Monitor.Exit(ChangedEvent);
}
I would be very greatful for a reply.
Thanks
Wolfram
|
|
|
|
|
You don't need to - and probably shouldn't - use both the Monitor and AutoResetEvent . Use one or the other.
The most likely problem is that you're locking the entire operation - this is virtually equivalent to doing these operations synchronously! Only lock when you need to. For example, unless you're synchronizing the same file between directories at the same time (and be careful, because the Changed event is fired exactly 3 times per changed file, no matter what the size), you can let the file copy operation occur in separate threads at the same time. Just lock when you need to write to the console or a file.
The timeout effect is occuring because the events are piling up and you're locking everything like I said above. You'll need to design your threads (using one of the methods I was talking about) so that the FileSystemWatcher can continue firing events without overloading the event queue so to speak.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
Hello Heath,
I use the msmq Framework now. The Filewatcher sends a message for each event. So, I can Sequentially work through the Messages and call the third-party-API one call after the other without loosing events or get concurrent API calls (with a certain loss of performance I must admit, but conceptual, this API is one big bottleneck... no multithreading, etc. .)
The ReceiveHandler is locked with only a Monitor, as you said.
It works, greetings
Wolfram
|
|
|
|
|
How can i make a control be not confined within the borders of its parent window or parent control? Is that even possible? Example I have a listbox inside a textbox, and is trying to mimic the autocomplete feature. What I want is when the listbox appears it should be completely visible, extending over the borders of the textbox.
|
|
|
|
|
You can actually use the auto-complete services that Windows provides. Take a look at this article: http://www.codeproject.com/csharp/csdoesshell4.asp[^].
And, no, controls can't paint outside their containers. In the case of the auto-complete window, it is an actual popup window so it doesn't have a container to which it's confined. A popup window is positioned and displayed appropriately and communicates with the control with which it's associated. You could also see the Platform SDK documentation for the IAutoComplete interface for more information as well.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
Thanks for the quick reply. I have actually read about that auto-complete service that Windows provides, but as I understood the dll required is found on XP and 2000 only. I might have clients who will still use windows 98 so Im trying to look for another option.
I guess I'm gonna go with the popup window route. Thanks again!
|
|
|
|
|
I'm writing a program that uses a TreeView control and a PropertyGrid. I've got several objects that users will be editing the properties of. What's supposed to happen is that the user will select an object from the tree, and then edit its properties in the grid.
I've been parsing the Node.FullPath property in my TreeView_AfterSelect function and then using that information to assign the correct object to the property grid. However, this is very time consuming.
It was suggested to me that a better way to do this might be to create my own child class of TreeNode, that contains a property that points to one of my objects. So... I created one base class that all of my other classes inherit from (SkinObject), created my child class of TreeNode (TreeNodePtr) and added a SkinObject property.
Now... how do I access that SkinObject property once inside my AfterSelect function? It doesn't seem as though a TreeNodePtr object is being passed in anywhere.
Any help with this would be greatly appreciated.
|
|
|
|
|
The TreeViewEventArgs.Node is what you're after. Since you derived a class from TreeNode , it's still your type (verify it with Node.GetType() ) but it's also a TreeNode - that's polymorphism. Just assign the Node property to your PropertyGrid 's SelectedObject property and you should see your SkinObject property. Don't even worry about casting it. For example, EVERY type in .NET derives from System.Object . While they are specific types, they are all objects and inherit the methods from Object (though some can be overridden):
object o = new TreeNode();
Console.WriteLine(o.GetType().FullName); You can further control the category, description, and many other design-time aspects of that property by using attributes in the System.ComponentModel namespace, like the CategoryAttribute and DescriptionAttribute .
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
Alright, I tried what you suggest, but here's the problem...
What I'm trying to do is assign the node's SkinObject object to the PropertyGrid. So something like prpSkinProps.SelectedObject = e.Node.SkinObject;
Unfortunately, when I try this, the compiler tells me that System.Windows.Forms.TreeNode doesn't have a property called SkinObject. Which it doesn't. Because TreeNodePtr does.
And obviously if I assign the Node itself to the Property Grid, then I see the properties of the Node, when what I want is the properties of the Node.SkinObject.
|
|
|
|
|
Instead, do:
prpSkinProps.SelectedObject = (e.Node as TreeNodePtr).SkinObject;
That way you're accessing it as a TreeNodePtr instead of a TreeNode.
|
|
|
|
|
Awesome. Works great. Thanks guys/gals.
|
|
|
|
|
I was about to tell you to cast. It's an important concept to understand when dealing with polymorphism.
There is actually a better way, though:
propertyGrid.SelectedObject = ((TreeNodePtr)e.Node).SkinObject; It's better because the as keyword acts as a cast that - if the cast is not successful - only returns null instead of throwing an InvalidCastException . This is better because it requires fewer instructions to perform and doesn't use a try-catch, which can be very expensive! Fortunately, even if the original TreeNode was not a TreeNodePtr , casting it will make it one so that an exception will not be thrown - SkinObject will be null, though, which will just reset the PropertyGrid . Either way, a simple cast is faster and will perform better.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
Ok, I have a new, related, question...
I need to find out the exact type of the SkinObject that's being passed in to the AfterSelect function. Some of them have a property that others don't, and depending on which one is selectd, a button needs to be enabled or disabled.
I've been trying to use the typeof function to retrieve this, but it's not working. For instance if I try something like:
Type t = typeof(((TreeNodePtr)e.Node).SkinObject);
the compiler just tells me that typeof is expecting a type.
I've figured that I can just add another property to TreeNodePtr, like a boolean or something, and just set it to true or false when I'm creating the TreeNode, but I figure there has to be a more elegant solution to this.
Any ideas?
|
|
|
|
|
typeof is a compile-time function. You need to use Object.GetType (always returns the right Type of the object), so you'd want to use:
Type t - e.Node.GetType() For reference types, you can also check with the is keyword:
if (e.Node is SkinObject)
{
} And here I thought GetType would've been the obvious choice!
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
>And here I thought GetType would've been the obvious choice!
hehe... well, it would have been except that I had typeof fresh in my mind from writing my typeconverters. :P
|
|
|
|
|
I have a textbox inside a user control that I set up to be right aligned to start. Then when the textbox receives focus, I want it to align left. Then when focused is lost, I want it to restore itself back to right alignment. I can get it to align itself left when focus is given to the textbox. But, when the user tabs off the textbox, it erases the text and keeps focus on the textbox. I tied into the enter and leave events and also tried it on the gotfocus and lostfocus events but I don't understand why it is erasing the text and why it is not giving focus to the next control. Any ideas would be very helpful. Thanks
|
|
|
|
|
The problem is with the order of events. When using the keyboard, the events are fired in the following order:- Enter
- GotFocus
- Leave
- Validating
- Validated
- LosFocus
When you use the mouse or call the Focus method, the events are fired in the following order:- Enter
- GotFocus
- LostFocus
- Leave
- Validating
- Validated
So, if you handle the Enter and LostFocus events, what you want works when using the keyboard. If you use the likely pairs together (like Enter and Leave ), when you change the TextAlign property the handle for the text control is recreated. If it had the focus (which for keyboard events, it still does) the focus is again set to the TextBox . This is why you couldn't leave. The text disappearing is again related to the handle of the text control (which is actually a wrapper for the Edit common control) being created at the wrong time so that the text isn't being restore because it wasn't there when the handle was recreated.
The trick is to change the alignment at the correct time based on whether or not a mouse button was clicked:
myTextBox.Enter += new EventHandler(myTextBox_Enter);
myTextBox.Leave += new EventHandler(myTextBox_Leave);
myTextBox.LostFocus += new EventHandler(myTextBox_LostFocus);
private void myTextBox_Enter(object sender, EventArgs e)
{
myTextBox.TextAlign = HorizontalAlignment.Left;
}
private void myTextBox_Leave(object sender, EventArgs e)
{
if (Control.MouseButtons != MouseButtons.None)
myTextBox.TextAlign = HorizontalAlignment.Right;
}
private void myTextBox_LostFocus(object sender, EventArgs e)
{
if (Control.MouseButtons == MouseButtons.None)
myTextBox.TextAlign = HorizontalAlignment.Right;
} Seems pretty whacky, but it works.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
Thank you very much. That worked
|
|
|
|
|
Here's my problem. I've added a Tree Control to my form. I've created my own child class of TreeNode (called TreeNodePtr), though, and I'm trying to use that. It's working fine, but everytime I change anything on the form in Design View, VS.NET changes all of the "new MyApp.TreeNodePtr(Test, "Test")" calls to things like (MyApp.TreeNodePtr)(System.Windows.Forms.TreeNode(Test, "Test").
I'm kind of new to this, but isn't this called a cast?
It's like the IDE knows I want to have a TreeNodePtr, but instead of just leaving it alone, it decides to cast it instead, and then it messes up all of my constructor calls.
|
|
|
|
|
Yes, it's a cast but there's really nothing you can do about it. The form and control designers do what they do. The only way to change it is to extend TreeView , create your own designer, and attribute your custom TreeView with the designer type you created. This isn't a trivial task, especially if you're new to .NET.
The other thing is to not use the designer! It's handy to initially layout controls on a form but it often becomes a hinderance. For example, I deal with a lot of localization but I hate how VS.NET does it. I rearrange quite a bit of code and move the ResourceManager out of InitializeComponents where VS.NET expects to find it. Since it doesn't, the designer breaks. I don't care though, because I stop using the designer long before that. It's the best way to truly learn what's going on instead of dragging-and-dropping your way to a simple application. Anyone can do that.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|