|
Greetings All,
I have a DataGrid bound to a DataTable. A particular column in my DataTable contains names in all uppercase. I would like to present this data in the grid capitalized (first character of each word uppercase the rest lower). What is the best way to achieve this?
Many Thanks,
Bitwise
|
|
|
|
|
Well, you could always NOT store them all in caps. :P
The best way is to use format specifiers, but you'll need to create a custom IFormatProvider to provide formatting for strings. Read my article, Custom String Formatting in .NET[^]. It gives you links to additional information.
Then, you must define table and column styles. See the DataGrid.TableStyles property documentation in the .NET Framework SDK for more information and an example.
Finally, on the DataGridTextBoxColumn bound to your column in question, assign the FormatInfo property to your IFormatProvider you created from the info above, and set the Format property to the specifier (if any).
For instance, you could create an IFormatProvider that when passed to various formatting functions calls creates a new string with the first character of each word capitalized and the rest of the characters in lower case. You could do ths many different ways.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Do you think I can convert a string of binary numbers, say, "110" to integers (should equals 6) using the IFormatProvider? Thanks
|
|
|
|
|
Yes, and if you look at my article I already go the other way (going back is trivial using the BitConverter ).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Greetings,
Thank you for the reply Heath! Great info! I have implemented the IFormatProvider and ICustomFormatter interfaces in a StringFormatInfo class as per your article. Works like a charm when tested with a String.Format call.
My problem is that my grid seems to be ignoring my DataGridTextBoxColumn.FormatInfo setting . Using breakpoints I see that I never enter the StringFormatInfo code. The indifference seems to be based on the underlying DataColumn's type ... which is System.String . If I set the .FormatInfo property for another DataGridTextBoxColumn in the grid, with an underlying System.Int32 DataType, the StringFormatInfo breakpoint is reached.
Thank You,
Bitwise
|
|
|
|
|
Interesting. Looking at the IL, I see that a type must implement IFormattable , which the String class does not! That's not good, nor typical.
There seems to be another way, though. You can set the PropertyDescriptor property using a PropertyDescriptor that describes your string. The set accessor for PropertyDescrptor uses that information to get a TypeConverter for your string. You can use this TypeConverter instead of the formatter, or use them in conjunction with each other (i.e., the TypeConverter could use the formatter you've created). It's a cludge, but it looks like it'd work.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
I'm trying to update the drag-and-drop mouse cursor when the user presses a shift key (SHIFT, CONTROL or ALT).
The problem is that although MSDN indicates that returning DragAction.Continue from the QueryContinueDrag handler fires a DragOver event (where I update the mouse cursor), this doesn't happen, so the cursor only updates when the user drags over another tree node, not when they press a key.
Here's what happens:
1. user drags a node.
2. DragOver returns DropEffects.Move .
3. user presses and holds the CONTROL key.
4. QueryDragContinue returns DragAction.Continue .
5. DragOver doesn't get called, so the cursor doesn't update to DropEffects.Copy .
PeteB
I wouldn't say "he's not the sharpest knife",
I'd say "he's a spoon."
|
|
|
|
|
All these events and related classes, structs, and enums actually use OLE drag and drop interfaces, as well as the DoDragDrop function. If you look at the DoDragDrop function documentation in the Platform SDK, you'll notice the supposed behavior is documented as well (i.e., calling IDropTarget::DragOver after S_OK is returned from IDropSource::QueryContinueDrag ).
There are no known bugs I can find related to this unusual behavior.
Have you tried setting breakpoints to see if perhaps your DragOver event handler isn't accomodating this properly?
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Well, it all seems to work with a form containing just a TreeView, so I guess I've got some digging around to do...
PeteB
I wouldn't say "he's not the sharpest knife",
I'd say "he's a spoon."
|
|
|
|
|
My bad.
I created a TreeView derived class to ease some of the drag-and-drop commonality, such as highlighting the target node and scrolling the tree, but to cut down on redrawing, I wasn't reacting if the dragged over node hasn't changed which would be fine if I called the base DragOver. =>
While we're on the subject, why doesn't the tree hightlight the drop-target node and how are you supposed to use the DragDropEffects.Scroll to get the tree to scroll?
PeteB
I wouldn't say "he's not the sharpest knife",
I'd say "he's a spoon."
|
|
|
|
|
A co-developer and I were in a discussion today about the right way to do this, I'd like some outside opinions on the subject.
Let's say we have a control that contains children of type Foo. Each child Foo can also contain children of type Foo.
To model the following, here's how I believe it should be modeled:
//////////// example #1, my solution ///////////////////
public class Foo
{
private FooCollection children = new FooCollection();
public Foo()
{
children.ItemAdded += SomeDelegate(this.ChildAddedCallback);
}
private void ChildAddedCallback(Foo addedChild)
{
}
public FooCollection Children
{
get
{
return this.children;
}
}
}
<pre>public class FooCollection
{
public event SomeDelegate ItemAdded;
public FooCollection()
{
}
public void Add(Foo item)
{
if(this.ItemAdded != null)
this.ItemAdded(item);
}
}
FooBarControl.Children.Add(foo);
foo.Children.Add(anotherFoo);
The developer I was discussing this with disagreed with the above code. He instead believes it should look something like:
//////////// example #2, the other developer's solution ////////////////
public class Foo
{
private FooCollection internalChildren = new FooCollection();
public Foo()
{
}
public void AddChild(Foo child)
{
internalChildren.Add(child);
}
public FooCollection GetChildren()
{
FooCollection externalChildren = new FooCollection();
foreach(Foo child in internalChildren)
externalChildren.Add(child);
return externalChildren;
}
}
<pre>public class FooCollection
{
public class FooCollection()
{
}
public void Add(Foo item)
{
}
}
FooBarControl.AddChild(foo);
foo.AddChild(anotherFoo);
His argument was that the above code is object-oriented, and all the functionality for adding a child is contained in a single class.
His main argument was that my code (sample #1) would allow external objects to invalidate the inner workings of Foo children. With his solution (example #2), the inner workings of Foo would be completely concealed. His solution would protect the inner workings and inner data of the Foo children. His solution also gives more of a de-coupling of the collection-to-Foo.
My argument was that my solution (example #1) follows that of the .NET FCL (look at TreeView w/ TreeNode for example, or any other control with children/items). I also argued that my solution is truely object oriented, using a seperate object to store and manipulate the children.
Additionally, my solution would allow for code reuse, in that the main FooBar control containing Foo items can also utilize the collection, without the need to write .AddChild methods for both the FooBar control and Foo item.
So, I'd like to hear from you all on how you guys would implement such a structure. Is example #1 or example #2 closer to what you would do/recommend?
---------------------------
He who knows that enough is enough will always have enough.
-Lao Tsu
|
|
|
|
|
He's making a case for encapsulation of the collection, which does give you better control. But ask yourself, do you need that much control over callers? Very few classes within the FCL encapsulate their lists and collections like this and instead expose them as you were doing: as properties. Yes, a caller could add, remove, and even clear your collection but decent code would accomodate that. That's the question you really have to answer in this case.
Another question is whether or not you want callers to be able to enumerate your collection. If not, then encapsulation is the way to go; otherwise, why waste the time?
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Thanks for the response Heath.
We certainly do want to be able to iterate over and enumerate the Foo items of the FooBar control. In fact, there are many methods in our main app that already do this, so that is a definite must.
Heath Stewart wrote:
Yes, a caller could add, remove, and even clear your collection but decent code would accomodate that.
Right. Our FooCollection already has methods for clearing, insert, remove, add, etc. and handles them all. As best as I can tell, there is no way for an external caller to break the control or corrupt the internal children via manipulation of the FooCollection.
As far as encapsulation goes, heck aren't we already doing some encapsulation via get/set accessors? I always thought that's one of the main uses of properties.
Anyway, with that in mind, and given the fact that Microsoft seems to expose collections as properties throughout the entire framework class library, I think I'll stick with my initial reaction, unless someone can point out how to break my code via access to the collection. (w/o using reflection of course!) :P
---------------------------
He who knows that enough is enough will always have enough.
-Lao Tsu
|
|
|
|
|
It depends what you mean by "breaking" your collection. For instance, I could reassign an object in your collection to another object. This - like many other things - comes down to a matter of trust. Do you trust your callers? If not, use code access security so that only your assemblies can call them, while all others get a SecurityException .
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
By breaking it, I meant manipulating the collection in such a way as to cause the collection to either throw an exception, display incorrect data, function improperly, open a security hole, etc. You bring up an interesting point in reassignment, that's something I didn't consider.
I suppose as long as FooCollection stores only Foo types, you'd only be able to reassign a Foo instance to another Foo instance. That is not a problem, since there is already checking going on to ensure each Foo can belong to only one FooBar control or other Foo item at a time. However, assigning a new Foo instance to an existing Foo in the FooCollection might not display correctly until the FooBar is repainted. I noticed the Sys.Win.Form.TreeView has such a case (bug?) in which the following code makes 2 nodes show up:
this.Show();
TreeView v = new TreeView();
this.Controls.Add(v);
v.Nodes.Add("hello");
TreeNodeCollection tnc = v.Nodes;
tnc[0] = new TreeNode("hello again");
MessageBox.Show(tnc.Count.ToString());
On the security side, currently there are no plans to use FooBar and Foo outside the main application. The only caller will be our main application. Still, it might be a good idea to eventually use CAS to ensure only fully trusted callers can manipulate the collection in the event other callers will use it.
Thanks again Heath for the response, you've been quite helpful as always.
---------------------------
He who knows that enough is enough will always have enough.
-Lao Tsu
|
|
|
|
|
There is a paper that discusses this subject, at Martin Fowler's website. See
http://martinfowler.com/ieeeSoftware/dataAccessRoutines.pdf
|
|
|
|
|
Interesting paper indeed, thanks for the resource.
---------------------------
He who knows that enough is enough will always have enough.
-Lao Tsu
|
|
|
|
|
I like your solution better.
His argument about that the coupling is incorrect. His solution is no more or less coupled than yours. Your solution breaks the coupling by using events which is a version of the observer design pattern developed to break the coupling of two classes in situations like this.
You can tweak you solution to make the inner workings of the Foo class just as concealed as his by creating a private nested subclass of FooCollection inside Foo . You can then override the Add method to do the necessary validation. This would also eliminate the need for the event as well and results in a very elegant design.
Aside from the nonstanard interface of his solution, which is awkward to me, the real problem I have with his code is the O(n) operation required to return a reference to the child collection.
|
|
|
|
|
His main argument is that my solution exposes the inner workings of the children, allowing for the possibility of breaking the whole thing, which is something I've discussed with Heath above. It is a valid point if I allow assignment of items from the collection.
I totally agree as far as the collection returning goes. That's gotta be terrible for performance for a tree with thousands of Foo items in it.
Good thinking on the subclass, I'd then be able to access the private methods of the parent from the subclass, which would eliminate the need for events as you mentioned.
Thanks for your input Brian.
---------------------------
He who knows that enough is enough will always have enough.
-Lao Tsu
|
|
|
|
|
I prefer your solution (#1).
I don't buy the argument that external objects could break the inner workings of Foo children. Foo is a class that happens to have property named Children. It's up that object (Children) to maintain it's own integrity, just as any other property of Foo. Foo's responsibility is to make sure all it's property values make sense as a whole, not that they make sense within themselves. If the Foo class is interested in knowing about special events in the Children object, it can listen to them using an eventhandler, just as you have done in your design.
I would say #2 is a bad design, because Foo must know too much about the Children object type (class). That's the FooCollection's responsibilities, and can be easily done with indexers, properties and events. If your friend has a problem with your solution not being OO enough, I would say his solution is less OO.
Is there a special circumstance in that the Children object is of type FooCollection, making this a tree structure? Really not. I think the same design patterns should apply.
A sligthly better solution would be that FooCollection contains objects that implement the IFoo interface. Possibly overkill, but could be useful.
Regards,
/Björn Morén
|
|
|
|
|
I am using c# to create web forms in .net and am trying to add hotkeys. I have been unsuccessful in locating any reference material. If anyone knows of any good reference sights on this subject it would be greatly appreciated or if it is a simple process and explanation would be even better.
Thanks,
Rick
|
|
|
|
|
Here's some sample code for you.
private void MyControl_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Insert:
if (e.Modifiers == Keys.Shift)
{
e.Handled = true;
}
return;
case Keys.Enter:
e.Handled = true;
return;
case Keys.Up:
if (e.Modifiers == Keys.Shift)
{
if (CanMoveItemUp)
{
MoveItemUp();
e.Handled = true;
}
}
return;
default:
return;
}
}
Tom Clement
Apptero, Inc.
|
|
|
|
|
You can also implenent hotkeys in your menus easily by simply assigning the MenuItem.Shortcut property to the key you want.
For global hotkeys in your application, see the IMessageFilter interface. Implement that and catch the WM_KEYDOWN message (0x0100), then use the Message.WParam member to get which key was pressed (matches up with the Keys enumeration). Using this concept, hotkeys are available throughout your application (if you desire) and you could even implement a simple key mapping to make them easy to change (for example, from a user interface for the benefit of a user). This is common in games, for example, like Quake that allow you to bind functions to practically any key you want.
You can add your implementation at any time using Application.AddMessageFilter .
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
You and other CPains didn't consider that original poster want to do that in a WEB form.
Mazy
"I think that only daring speculation can lead us further and not accumulation of facts." - Albert Einstein
|
|
|
|
|
True. Far be it for us to assume that someone would use the right forums.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|