|
The controls are separate controls without any sort of policy allow for a single selection among different instances of the same control (like a radio button). What you've done isn't really a hack but a necessity, but there are alternatives you could consider.
Perhaps write a class that really is just a collection of your ListViewItemCollection instances for each ListView . You could implement an event handler on that class that listens for ListView.SelectedIndexChanged and uses state to ignore the next raised event since you'll be selecting a new item. That hanler (or some other callee) would then clear the selection for the other ListViewItemCollection instances.
Below is a really quick sample I threw together of such a manager:
using System;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;
class Test : Form
{
static void Main(string[] args)
{
bool mutuallyExclusive = false;
try
{
if (args.Length > 0)
{
mutuallyExclusive = bool.Parse(args[0]);
}
}
catch
{
Console.Error.WriteLine("Invalid argument; expecting \"true\" or \"false\".");
Environment.Exit(87);
}
Application.Run(new Test(mutuallyExclusive));
}
Test(bool mutuallyExclusive)
{
ListView[] views = new ListView[] {
new ListView(),
new ListView()
};
foreach (ListView view in views)
{
view.HideSelection = false;
for (int i = 0; i < 5; i++)
{
ListViewItem item = new ListViewItem("Item " + i);
view.Items.Add(item);
}
}
Controls.AddRange(views);
views[0].Name = "view1";
views[0].Location = new Point(8, 8);
views[0].Size = new Size(200, 100);
views[1].Name = "view2";
views[1].Location = new Point(views[0].Width + 8, 8);
views[1].Size = views[0].Size;
Width = 24 + views[0].Width + views[1].Width;
Height = 24 + views[0].Height + views[1].Height;
new ListViewSelectionManager(mutuallyExclusive).AddRange(views);
Text = "Mutually Exclusive ListView Selection Example";
}
}
public class ListViewSelectionManager
{
bool mutuallyExclusive = false;
ArrayList views = new ArrayList();
bool clearing = false;
public ListViewSelectionManager(bool mutuallyExclusive)
{
this.mutuallyExclusive = mutuallyExclusive;
}
ListViewSelectionManager() {}
public void AddRange(ListView[] views)
{
foreach (ListView view in views)
{
view.SelectedIndexChanged += new EventHandler(OnSelectedIndexChanged);
this.views.Add(view);
}
}
void OnSelectedIndexChanged(object sender, EventArgs e)
{
if (sender == null) throw new ArgumentNullException("sender");
Control c = sender as Control;
Console.WriteLine("SelectedIndexChanged event raised from " + c.Name);
OnListViewSelectionChanged(sender, e);
if (mutuallyExclusive && !clearing)
{
clearing = true;
foreach (ListView view in views)
{
if (sender != view)
{
Console.WriteLine("Clearing selection for " + view.Name);
view.SelectedItems.Clear();
}
}
clearing = false;
}
}
public event EventHandler ListViewSelectionChanged;
protected virtual void OnListViewSelectionChanged(object lv, EventArgs e)
{
if (ListViewSelectionChanged != null)
{
ListViewSelectionChanged(lv, e);
}
}
public ICollection SelectedItems
{
get
{
ArrayList list = new ArrayList();
foreach (ListView view in views)
{
list.AddRange(view.SelectedItems);
}
return list;
}
}
}
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Heath Stewart wrote:
The controls are separate controls without any sort of policy allow for a single selection among different instances of the same control (like a radio button). What you've done isn't really a hack but a necessity, but there are alternatives you could consider.
I'd suspected as much, but was hoping there might be a way to differentiate between a user change of selection and a programatic one, since I only wanted clearing on the former.
With only 2 lvs on the form, the containerclass idea is serious overkill for my current needs/
|
|
|
|
|
The only way to detect programmatic vs. user-click is to get the current mouse position, translate that to client coordinates from screen coordinates, and detect if the mouse is over a particular ListViewItem . It actually gets pretty messy.
dan neely wrote:
With only 2 lvs on the form, the containerclass idea is serious overkill for my current needs/
As you know if programming, change is the only constant ( or those things declared with const ) The manager idea is actually pretty simple and very flexible and is scalable for future needs. It also keeps from writing spaghetti code. The goal of object-oriented programming is to encapsulate concepts and code into re-usable classes, and the manager approach is one such way of doing that. Rather than writing similar (if not the same) code for a specific sequence every time you need it you can reuse this class and encapsulate all the selection code inside it. It's just an abstract approach to solving the problem and just one idea for handling it.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Heath Stewart wrote:
The only way to detect programmatic vs. user-click is to get the current mouse position, translate that to client coordinates from screen coordinates, and detect if the mouse is over a particular ListViewItem. It actually gets pretty messy.
I'm trapping doubleclicks in two columns on one lv so I've got a fair idea of what's involved in that route, I don't think it's that ugly though. An addition to the framework allowing for a direct check of what cell was clicked on would be a nice improvement though.
|
|
|
|
|
That would be a useful feature. To make such suggestions or reports possible bugs please use the MSDN Product Feedback Center[^]. That ties in with our internal defect tracking system so I promise we're listening! Please keep in mind, however, that .NET 2.0 features are already locked down.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Heath Stewart wrote:
That would be a useful feature. To make such suggestions or reports possible bugs please use the MSDN Product Feedback Center[^]. That ties in with our internal defect tracking system so I promise we're listening! Please keep in mind, however, that .NET 2.0 features are already locked down.
Is there any way to specify v1.1 as the version? I only see v2.0 betas available in the combo box?
|
|
|
|
|
It would be a design change request for a future version. Just specify one of the v2.0 betas or any future versions and it will get moved as needed. You can request that it be added to v1.1 but we typically don't add features to a previous version.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
How to save change from sql db table (as we take Differential Backup of db) in script form. And run script through C#.Net coding.
|Muhamad Waqas Butt|
waqasb4all@yahoo.com
www.sktech.freewebspace.com
|
|
|
|
|
I am a student busy developing an application in C# donet, I am busy working with crystal reports. I need my reports to be dynamic, I want to pass a different SQL statement every time (eg a report that will generate information of the selected customer)
string SQL = "SELECT ClientID, Name FROM Client WHERE ClientID = 14544";
DataSet ds = new DataSet();
System.Data.OleDb.OleDbConnection conn = new System.Data.OleDb.OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;Initial Catalog=TKOAcademic;Integrated Security=SSPI;Connect Timeout=30");
System.Data.OleDb.OleDbDataAdapter oleDbDataAdapter1 = new System.Data.OleDb.OleDbDataAdapter();
oleDbDataAdapter1.SelectCommand = new System.Data.OleDb.OleDbCommand(SQL, conn);
CrystalReport1 cutsReport = new CrystalReport1();
oleDbDataAdapter1.Fill(ds,"Client");
cutsReport.SetDataSource(ds);
crystalReportViewer.ReportSource = cutsReport;
I have tried doing it but shows all the records from the Client table
|
|
|
|
|
You need to use parameters. There are good examples at Business Objects. The have a .Net starters guide at http://www.businessobjects.com/jump/xi/default.asp[^] that was very helpful. If you also reference their knowledge base, they have many examples of how to set up running a report from within you app as you seem to be attempting.
|
|
|
|
|
Has anyone read the following book?
Pro .Net 1.1 Remoting, Reflection, and Threading
It looks like just the book i need, but i can't find a review (even by the publisher) anywhere on the web.
Comments would be appreciated.
Thanks,
Russ
|
|
|
|
|
How's the author? Maybe I've read the Italian translation.
___________________________________
Tozzi is right: Gaia is getting rid of us.
My Blog [ITA]
|
|
|
|
|
Pro .Net 1.1 Remoting, Reflection, and Threading
Syed Fahad Gilani, Mike Gillespie, James Hart, Benny Mathew, Sandra Gopikrishna, Andy Olsen
One of the reasons i asked was because there were so many authors, in the past i've found that books with this many people can be a bit incoherent. I suppose that comes down to how well it's editted really.
Thanks for replying,
Russ
|
|
|
|
|
Hello,
I have a little problem when saving my xml file.
I use an instance of System.Xml.Document.
I load an xml document file and edit this file with an application, then when I save it (doc.save("file.xml") ), I would like also the whitespaces being saved.
Exemple:
<element>
<subElement> </subElement>
</element>
It saves correctly the whitespaces, but when I read it again, the whitespaces are trimmed!
To prevent that, I would like to replace whitespaces by :   but on saving the xml writer encodes this sequence into : &#32; and therefore it is not interpreted as a whitespace anymore...
Any help would be really appreciated, thanks in advance!
-- modified at 10:12 Wednesday 28th September, 2005
|
|
|
|
|
I don't think you can get it to retain the whitespace when it's read. Special characters will not get interpreted as whitepsace either.
I'm curious, why would you want the whitespace in there? I can't think of a reason to do it.
You MIGHT be able to get away with putting in attributes into your nodes that specify how many spaces to put into the data when you retrieve the data. Something like:
<element>
<subElement wsPrefix=8 wsPostfix=3>mydata</subElement>
</element>
When you go to retrieve the element, read the wsPrefix and wsPostfix attributes and add the number of spaces to your data accordingly.
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
Hi, thanks for your idea, I will think about it.
The reason I need a white space is because I have some subElements that I want to concatenate
like "someData"+WHITESPACE+"someData".
for example:
<element>
<subElement type="data">someData</subElement>
<subElement type="caption"> </subElement>
<subElement type="data">someData</subElement>
</element>
I found this really weird that the xmlReader does not interpret one or more whitespace in the Innertext part of an element... don't you think so?
|
|
|
|
|
I have been trying to figure out a memory leak for quite some time. I've ignored what C# is supposedly taking care of but now that is the only thing I have left. And...I discovered something I'm confused about.
Add a new form to a project and drop some components on it. You will find
private System.ComponentModel.Container components = null;
and
protected override void Dispose( bool disposing )<br />
{<br />
if( disposing )<br />
{<br />
if(components != null)<br />
{<br />
components.Dispose();<br />
}<br />
}<br />
base.Dispose( disposing );<br />
}
But there will be no further reference to the use of components.
Therefore, when I dynamically create a form frmDialog(), do what I have to do, then Dispose() of the form, it fails the if(components != null) check and the components are never released. I even set the form to null (which I know I shouldn't do) but that still left the form defined. In the main form, frmDialog still exists as a defined object. In frmDialog() I add my own Dispose() calls for my classes and they show as undefined but every component of the form is still defined. I suspect that is why my memory is never released; because the form components haven't been released (showing <<undefined value="">>) the form can't release.
1) My understanding is "Don't do any maintenance within the #region Windows Form Designer generated code section so how do I get the components of the form into the variable components so they can be destroyed?
or
2) Is there a routine I can add to the Dispose() method to dispose of all the components by hand? Why would I have to do this?
Thanks.
|
|
|
|
|
What has made you come to the conclusion that you have a memory leak?
dbetting wrote:
it fails the if(components != null) check and the components are never released
If the components reference is null, there are no components needing disposal. If there are components that needs disposal, they are added to the components collection in the generated code.
dbetting wrote:
I even set the form to null
You can't set the form to null. You can set a reference to the form to null, but that doesn't affect the form.
---
b { font-weight: normal; }
|
|
|
|
|
This particular form is opened from several places within the program. It is used to review information about existing orders in the system. Every time it opens, the executable grows by about 3MB. After a couple of hours, the user session is at hundreds of MB.
Guffa wrote:
If the components reference is null, there are no components needing disposal. If there are components that needs disposal, they are added to the components collection in the generated code.
This is what has me confused. No place in the form code is components referenced.
Stepping through Dispose() of the form, when on the last brace, all the objects I have created are now showing undefined (I did have two that did not dispose properly). The only thing left at that point are the various components as defined objects. components evaluates as null and therefore the line components.Dispose(); is never reached.
using (frmContainer FrmMasterParts = new frmContainer())
{
FrmMasterParts.SetSalesOrderInfo(SelectedOrderNumber, SelectedReferenceNumber);
FrmMasterParts.ShowInTaskbar = false;
FrmMasterParts.StartPosition = FormStartPosition.CenterParent;
FrmMasterParts.ShowDialog();
}
Instantiating and calling the form is as straight forward as can be (above code). The dispose of FrmMasterParts does execute and that is what I was stepping through (shown in original message).
Guffa wrote:
You can't set the form to null. You can set a reference to the form to null, but that doesn't affect the form.
Just to see what would happen, I attempted to set FrmMasterParts to null. Unless I'm mistaken, if that did work, that would've made the memory block unreachable and it would never be released. At least that was the case in Delphi. I was just curious and surprised by the result. FrmMasterParts remained defined and unchanged.
|
|
|
|
|
The Timer control for an example is a component that needs disposal. When you place a Timer control on the page, it will be added to the components collection, and will be disposed when the form is disposed.
Most controls in a form doesn't need disposal. They are fully managed, and will be collected by the garbage colector.
If you have a memory leak, it's much more likely on some object that you have created yourself, than in the code for the form.
dbetting wrote:
Just to see what would happen, I attempted to set FrmMasterParts to null. Unless I'm mistaken, if that did work, that would've made the memory block unreachable and it would never be released. At least that was the case in Delphi.
The memory management is different in .NET from Delphi or other languages using memory allocation/deallocation. The memory is not deallocated, it's collected by the garbage collector. You don't have to free the memory that is allocated. You just let the reference to the object go out of scope, and the object will be collected by the garbage collector.
The Dispose method of an object doesn't free the memory either. It's only used to dispose of unmanaged resources that the object uses. The memory used by the object itself is just left for the garbage collector to clean up.
---
b { font-weight: normal; }
|
|
|
|
|
Your problem is the .ShowDialog() call. When using ShowDialog, you MUST call .Dispose() on the Form object when you're done using it. Closing a .ShowDialog() Form does not actually close the form, as it's just hiding. The .Close() method of a Form is not called when using .ShowDialog() .
using (frmContainer FrmMasterParts = new frmContainer())
{
FrmMasterParts.SetSalesOrderInfo(SelectedOrderNumber, SelectedReferenceNumber);
FrmMasterParts.ShowInTaskbar = false;
FrmMasterParts.StartPosition = FormStartPosition.CenterParent;
FrmMasterParts.ShowDialog();
.
.
.
FrmMasterParts.Dispose();
}
This is not necessary when using a Form's .Show() method.
Form.ShowDialog Method ()[^] documentation on MSDN.
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
-- modified at 15:37 Wednesday 28th September, 2005
|
|
|
|
|
My understanding of using using() was that you don't have to worry about the dispose. That's why it was one of the first things I did when the leak showed was made evident. I replace all declarations with the using() structure.
But, to make sure, I added the line. Didn't cause a problem but didn't fix it either.
The line after the braces I had a break point. Nowhere in this. (using the Autos tab) is there any reference to FrmMasterParts. But, when the program started, I had 35MB memory in use. 15 executions of showing this form put the memory at 100MB. I just added System.GC.Collect() after the brace. Still the same result.
|
|
|
|
|
Whoops! My mistake. I misread your using line and though it wsa for a different object. using will call the .Dispose() method for you.
You've got to have another object that you're not disposing, like a Bitmap maybe?
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
Based on these conversations, I've tried a few other things. Inside FrmMasterParts, I've stepped through the creation of it and each UserControl I create inside of it. Each item I've created, I ensure there is a Dispose() or a null set to it in the Dispose() method (The enums and such didn't like that so I took them back out!). Literally, if it wasn't a form component, I added it to the Dispose(). I did this for the form and each UC.
When executing the program, upon the second and successive instantiation of FrmMasterParts, it's entire content (with the exception of the components) has everything set to undefined (as expected). This would validate that a clean copy of the form is being created with the using() . Upon display of the form, the additional memory is added. Upon the last brace of the using() , FrmMasterParts is no longer accessible but the memory has not been release. Execute GC.Collect(). Still no luck.
The last time I used a memory tool was the early '90's. Do you know of one that I can try to look at the physical memory to get an idea of what is being left out there?
An interesting note: When I minimize my 100MB program, task manager drops by about 99MB. Maximize again. I can do all kinds of stuff and memory stays small. Click the button to open this form, almost all 99MB comes back. Evaluate the content of FrmMasterParts in Autos, and it is empty as discussed above.
This is going on on my Dell laptop, a Compaq laptop as well as the development workstation and production servers so it isn't hardware related.
Thanks for your time.
|
|
|
|
|
OK. First, setting something to null isn't necessary. Once the object can't be reached any more, the GC will get around to collecting it.
What do you have that's allocating that much stuff?!
The problem you're running into is that you have unmanaged (not under the .NET memory manager control) resources being consumed and not released by one, or more, of your components on that form. There's a component that isn't releasing unmanaged memory and/or other resources, such as handles.
Oh! Task Manager is probably the worst tool you could use to track the memory usage of a managed application. Use the Performance Monitor with the .NET Framework counters or something like the CLR Profiler[^].
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
-- modified at 20:30 Wednesday 28th September, 2005
|
|
|
|
|