-
Posts
53 -
Joined
-
Last visited
Content Type
Profiles
Forums
Blogs
Events
Articles
Resources
Downloads
Gallery
Everything posted by Quercus
-
Well Fudge! This is where I need a smiley of Homer Simpson going D'oh!That was it, fixed the return type and all is well. I've been staring at this for two days now and just didn't see it. Thanks.
-
Got the debugger working, thanks. But I still can't solve my problem. I�m back to my test application, which is attached below. My control now has a collection of collections. Yup, the user control saves a collection of style objects. Each style object in turn has a sub collection of other style objects. I know the implementation in the test control is a useless feature, but it makes sense in my real control, trust me. The first collection is being saved nicely, and any straight properties of the objects in the first collection are also being saved. However, the sub collection is not being serialized, and none of the sub objects are being serialized. I'm getting the error: "Code generation for property 'SubItem' failed. Error was: 'Object reference not set to an instance of an object.'" (SubItems, by the way, is the property name for the second collection.) Both collection items have a type converter, and both collection properties are set to serialize content. Is there anything else I need to do? Do I need two ControlDesigners maybe? Any thoughts? Just had a thought: Do I need to do a separate PropertyDescriptor PropImChanging = TypeDescriptor.GetProperties(MyControl)["SubItems"]; c.OnComponentChanging(MyControl, PropImChanging); for the sub collections? In other words, will Serialize.Content only go one deep? If so, how would I sequence this? [TypeConverter(typeof(TextDataTypeConverter))] public class TextData { // Stuff public TextData(string Name, Color color) {...} public string Name {...} public Color BackColor {...} public Color ForeColor {...} [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public TextSubCollection SubItems { get { return subItems; } } } [TypeConverter(typeof(SubItemTypeConverter))] public class SubItem { private string myValue = ""; public SubItem(string MyValue) { myValue = MyValue; } public string MyValue { get { return myValue; } set { myValue = value; } } } public class TextDataCollection : CollectionBase { public TextData this[int index] {...} public int Add(TextData item) {...} public TextData GetDataByName(string Name) {...} } public class TextSubCollection : CollectionBase { public SubItem this[int index] {...} public int Add(SubItem item) {...} } internal class TextDataTypeConverter : TypeConverter { public override bool CanConvertTo(ITypeDescriptorContext context, Type destType) { // Boiler Plate } public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destType) { if (destType == typeof(InstanceDescriptor)) { ConstructorInfo ci = typeof(TextData).GetConstructor( new Type[]{typeof(string), typeof(Color)} ); TextData td = (TextData)value; return new InstanceDescriptor(ci, new object[]{td.Name, td.BackColor}, false); } return base.ConvertTo(context, culture, value, destType); } } internal class SubItemTypeConverter : TypeConverter { public override bool CanConvertTo(ITypeDescriptorContext context, Type destType) { // Boiler Plate } public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destType) { if (destType == typeof(InstanceDescriptor)) { ConstructorInfo ci = typeof(TextData).GetConstructor( new Type[]{typeof(string)} ); SubItem si = (SubItem)value; return new InstanceDescriptor(ci, new object[]{si.MyValue}, false); } return base.ConvertTo(context, culture, value, destType); } } // From inside the handler for the designer verb: // Add a new text style h = (IDesignerHost) GetService(typeof(IDesignerHost)); newItem = new TextData("Blue", Color.Blue); newItem.ForeColor = Color.Gold; subItem = new SubItem("Blue One"); newItem.SubItems.Add(subItem); subItem = new SubItem("Blue Two"); newItem.SubItems.Add(subItem); dt = h.CreateTransaction("Add TextStyle"); c = (IComponentChangeService) GetService(typeof(IComponentChangeService)); PropertyDescriptor PropImChanging = TypeDescriptor.GetProperties(MyControl)["TextDataCollection"]; c.OnComponentChanging(MyControl, PropImChanging); // Add a new property MyControl.TextDataCollection.Add(newItem); c.OnComponentChanged(MyControl, TypeDescriptor.GetProperties(MyControl)["TextDataCollection"], null, null); dt.Commit(); [/Code] SerializationTest.zip
-
Thanks again. I'm back to working on my real project as opposed to the test application, and I think it will be difficult to put all the item data into the constructor, but I'll take a good look at it. I'm still having some problems - I'm getting a null reference error - that I can't track down. Man! Debugging the designer is a PITA! I've seen some posts on how to start a second VS.NET instance and use it to debug the designer running in the first instance. I've tried: 1) Put your control on a form in VS.NET 2) Start a 2nd Vs.Net 3) Choose the Debug menu >> Processes ... 4) Double click "devenv.exe" and choose "Common Language Runtime" as the types of debugging 5) Open your code file, set your breakpoint, and you're debugging. When I try this, the 2nd instance is essentially blank. I set my breakpoint in the 1st instance, but the code never stops. I know the code is making it to the break points because I have MessageBox objects here and there letting me know what is going on. Is it possible to use the debugger for a control designer?
-
Okay, Devil, I've got another question: Suppose that the objects being serialized cannot be fully described by their constructor. For example, say I add a new property to the TextData object for a ForeColor, that is not included in the constructor. Then creating new text styles would look something like: // Create the new item(s) c = (IComponentChangeService) GetService(typeof(IComponentChangeService)); newItem = new TextData("test", Color.Red); newItem.ForeColor = Color.DeepSkyBlue; c.OnComponentChanging(MyControl, TypeDescriptor.GetProperties(MyControl)["TextDataCollection"]); MyControl.TextDataCollection.Add(newItem); c.OnComponentChanged(MyControl, TypeDescriptor.GetProperties(MyControl)["TextDataCollection"], null, null); But when I try this, the "Test", Color.Red is serialized, but not the ForeColor property. Is this something that needs to be addressed in the TypeConverter for the TextData class? I'm still searching MSDN for this but I haven't found the answer yet. Can you point me in the right direction? Thanks again.
-
Making Only a Currently Opened Form Accessible
Quercus replied to rustyfancy's topic in Windows Forms
Use the ShowDialog method of Form2: // C# Form2 MyForm = new Form2; MyForm.ShowDialog; ' VB Dim MyForm as new Form2 MyForm.ShowDialog() -
Ah! Excelent! Thanks Devil! I never would have gotten here without your help via this forum and your tutorials. If I add an AddRange method to the collection class, and then add repeated new styles to the control, will the designer automatically use the AddRange method instead of repeated Add calls, or do I need to use AddRange myself, or do something else special, when I add the new styles? I had to add a DesignerTransaction to enable the undo/redo, and I was getting an error when the designer tried to serialize the normally read/write BackColor property. So I've made the following tweaks: // In my CustomText Control class: [browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new Color BackColor { get { return base.BackColor; } } // The event handler for the designer verb in the ControlDesigner private void ConfigureItemStylesEventHandler(object Sender, System.EventArgs e) { // Declare some objects IDesignerHost h; DesignerTransaction dt; IComponentChangeService c; TextData newItem; // Get some services we'll need h = (IDesignerHost) GetService(typeof(IDesignerHost)); // Initialize a designer transaction. This will start 'recording' our actions // so that the designer can undo them if we want. dt = h.CreateTransaction("Add TextStyle"); // Create the new item(s) c = (IComponentChangeService) GetService(typeof(IComponentChangeService)); newItem = new TextData("test", Color.Red); c.OnComponentChanging(MyControl, TypeDescriptor.GetProperties(MyControl)["TextDataCollection"]); MyControl.TextDataCollection.Add(newItem); c.OnComponentChanged(MyControl, TypeDescriptor.GetProperties(MyControl)["TextDataCollection"], null, null); // Finally, commit the changes to the designer transaction. This // will stop the dt from recording our actions. dt.commit(); // We're done. } [/Code] Thanks for all your help.
-
Alright, that was a bit overboard. Let me simplify this a bit if I can. I have a control where one of its properties is a collection of objects that I need to have serialized: [browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public TextDataCollection TextDataCollection { get { return theItems; } // where theItems is a collection of my TextData objects. } Each TextData object in this collection is defined fully by the constructor public TextData(string Name, Color color) { name = Name; backColor = color; } [/Code] I also have a type converter for the TextData object. I thought this was all I needed to have the data serialized so that it can be persisted, but it is not serializing. Are there other steps I need to do? Thanks.
-
I have a TextBox control where instead of specifying BackColor, Font, ForeColor, you can specify a list of named styles in the control. Then you can select by name which one of the styles to use. It’s a pretty useless feature, but this is only a test project to work out some designer issues for a more complicated control I’m working on. My problem is that when I add styles to the control at design time (using a designer verb and custom entry form), they are not being serialized. I have followed Devil’s excellent tutorial on Designers for Collection Controls. However, his sample has collections of components. I don’t have any components, I simply have a collection of objects. Therefore, I don’t think I can use the IDesignerHost services discussed in his tutorial. Do you need to use IDesignerHost services to tell the IDE to serialize your control, or only if you are using components? Below are the highlights of this control. The full code is attached as a ZIP. Hope someone has some ideas or can point me in a new direction. Thanks. [Designer(typeof(CustomTextDesigner))] public class CustomText : System.Windows.Forms.TextBox { private TextDataCollection theItems; private string backStyle; // Stuff and more stuff here [browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public TextDataCollection TextDataCollection { get { return theItems; } } public string BackStyle { get { return backStyle; } set { backStyle = value; try { base.BackColor = theItems.GetDataByName(value).BackColor; } catch { base.BackColor = Color.Violet; // I just want to see when this fails. } } } } internal class CustomTextDesigner : System.Windows.Forms.Design.ControlDesigner { CustomText MyControl; // Assigned to component in the Initialize method // Stuff and more stuff here. // This is the event handler to my designer verb! private void ConfigureItemStylesEventHandler(object sender, System.EventArgs e) { IDesignerHost h; DesignerTransaction dt; IComponentChangeService c; TextData newItem; // // This is Devil's code in his demo project // dt = h.CreateTransaction("Add Button"); // button = (ColourButton) h.CreateComponent(typeof(ColourButton)); // c.OnComponentChanging(MyControl, null); // MyControl.Buttons.Add(button); // c.OnComponentChanged(MyControl, null, null, null); // dt.Commit(); // This is my attempt to implement Devil’s code to my uses. h = (IDesignerHost) GetService(typeof(IDesignerHost)); c = (IComponentChangeService) GetService(typeof(IComponentChangeService)); dt = h.CreateTransaction("Add TextStyle"); newItem = (TextData) h.CreateComponent(typof(TextData)); // Trouble here. I get the compile error: // 'SerializationTest.TextData' denotes a 'class' where a 'variable' was expected // I suspect this is because TextData does not inherit from Component. // What do I do? // Another problem is that TextData takes two parameters in its constructor. // One is a string that is the object’s name, and one is a Color that is // the object’s color. How do I use the services to create an object with // constructor parameters? // // This is my original code. This did not serialize. // newItem = new TextData("Red", Color.Red); // MyControl.TextDataCollection.Add(newItem); // // newItem = new TextData("Blue", Color.Blue); // MyControl.TextDataCollection.Add(newItem); // // newItem = new TextData("White", Color.White); // MyControl.TextDataCollection.Add(newItem); } } [TypeConverter(typeof(TextDataTypeConverter))] public class TextData { private string name = ""; private Color backColor = Color.White; public TextData(string Name, Color color) { name = Name; backColor = color; } // Name and Color properties here. } public class TextDataCollection : CollectionBase { // This is a simple collection class to hold the // collection of TextData objects. The implementation // is not shown here. } internal class TextDataTypeConverter : TypeConverter { public override bool CanConvertTo(ITypeDescriptorContext context, Type destType) { if (destType == typeof(InstanceDescriptor)) return true; return base.CanConvertTo(context, destType); } public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destType) { if (destType == typeof(InstanceDescriptor)) { ConstructorInfo ci = typeof(TextData).GetConstructor( new Type[]{typeof(string), typeof(Color)} ); TextData td = (TextData)value; return new InstanceDescriptor(ci, new object[]{td.Name, td.BackColor}); } return base.ConvertTo(context, culture, value, destType); } } SerializationTest.zip
-
Sandbar is not the direction I'm going in, but thanks anyway. As far as the subclassing approach you are talking about, I'll have to look into this a bit. Got any links that will start me in the right direction? Got any techniques I can use to force another control on top of the inherited combo box? Thanks.
-
Thanks Devil. I got a lot out of your DesignTime support tuturials and have used it elsewhere in this project. Problem is, DropDownList does work, but that's not what I want. I want the user to be able to edit the text or enter his/her own. And because of the way I have formatted the data here, I will probably need to implement this functionality manually as well. So it brings be back to square one. I still need to be able to either directly draw to the text area of the control, or I need to be able to place a different control on top of the combo box. Any thoughts on how I can do these?
-
ARRGH! I've been experimenting with placing a blank Control on top of my inherited ComboBox. The ComboBox still draws on top of my empty control! public MyCombo() { // This call is required by the Windows.Forms Form Designer. InitializeComponent(); // Place a blank control on top of this one for me to // draw on myself // Create new control. TextArea, declared earlier, is // just a blank control. Its only function is a slate that // I can draw to. textArea = new TextArea(); // Place it on the control. This method sizes it to fill // just the areas of the combo box I want it to. LocateTextArea(); // This should show an Aqua colored slate in front of the normal // text area of the combo box. textArea.BringToFront(); this.Controls.Add(textArea); textArea.BackColor = Colors.Aqua; textArea.Show(); } Even with this, the text area of the control show up as if it was alone. textArea is only visible as a few pixels here and there. Is there any way that I can paint on top of the combo box text area???? Thanks.
-
I'm working on a custom ComboBox control that displays its data in a highly formatted maner. Letting the ComboBox draw the data itself won't do for my purposes. I've already used the OnDrawItem to show my data in the drop down portion just the way I want it. The problem is, once a selection is made, it shows up in the main control in the same old bland appearance. I need to override the normal control painting. The combo box rarely, if ever, calls the OnPaint method. So I've used the WndProc method to trap for WM_PAINT: protected override void WndProc(ref Message m) { const int WM_PAINT = 0xF; // Let base process the message first. base.WndProc (ref m); // Check what message was sent. if (m.Msg == WM_PAINT) { IntPtr hdc = GetDC(this.Handle); Graphics G = Graphics.FromHdc(hdc); // This will fill the whole thing with BlueViolet. Not what I really want // but will demonstrate if this is working or not. G.FillRectangle(System.Drawing.Brushes.BlueViolet, this.ClientRectangle); } } [/Code] What I get is a control that has Violet in all areas [b]except[/b] for the data region, which is what I want to paint. I.e. the border and down button areas are a solid violet, but the text area is unchanged. It would appear that either it is not letting me draw in the data area, or it is re-painting after I paint. Does anyone know how I can override the ComboBox's painting so that I can draw my data just the way I want? My only other thought is to place a TextBox/Label/RichTextBox over the text region of the control and draw to that, but I'd rather not do this if I don't have to. Thanks.
-
Thanks. WinUser.h had the most information I've seen yet. But I would hardly call it user-friendly. What I would really like is a catalog with names, values and descriptions of all, or at least the most common, windows messages. Does this exist anywhere?
-
Where can I find a nice user-friendly catalog of Windows Messages for use with the WinProc method? The documentation says to look in windows.h, but the one I have was only about 20 lines long and didn't contain squat.
-
I have not tried this, but from what I have seen, this is not a simple problem to solve and can't be done with simple tabs. Run a search for "multi column combobox" and "multi column list box" and you will find solutions. In any event, you will probably find that you need to either handle the OnDrawItem event, or create your own control. You might want to check out these: www.codeproject.com/cs/combobox/multicolumncombo.asp www.codeproject.com/cs/combobox/MultiColumnListBox.asp http://www.codeproject.com/vb/net/multicolumncombo.asp There is more out there. Good luck.
-
After following up on some of the issues Denaes has asked about, I fixed a bug in the control (I'm sure more remain!) and have re-posted it below. Also, when you first open the demonstration project, please build it, otherwise the MulitCombo control won't show up on the form. Please see the ReadMe and comments in MultiCombo.cs for more. Thanks. multiitemcombo.zip
-
Perhaps this should be taken off line unless others are having the same problem. What happens when the program is first run? It should come up with a MultiCombo that is already bound to the data set, although the list box is not. The list box won't bind until you press one of the Bind DB (or other) buttons. Do you even see the MultiCombo when the program is run? The MultiCombo is created in the windows generated section: this.multiCombo1 = new MultiItemCombo.MultiCombo(); // other code here // // multiCombo1 // this.multiCombo1.DataMember = "Contacts"; this.multiCombo1.DataSource = this.dsNames1; this.multiCombo1.DisplayMember = "LastName, State"; this.multiCombo1.DividerColor = System.Drawing.Color.Black; this.multiCombo1.DividerWidth = 0F; this.multiCombo1.Location = new System.Drawing.Point(8, 144); this.multiCombo1.Name = "multiCombo1"; this.multiCombo1.Size = new System.Drawing.Size(232, 21); this.multiCombo1.TabIndex = 1; this.multiCombo1.Text = "multiCombo1"; If this is in your code, you should see the control at design time. Any stepping though code you can do to find the null reference would be helpful. I presume that it is the dsNames1 data set. Please check to make sure the connection is properly established and the data set is being created. If not, you might try to nuke my data tools and create a new set (Data Adapter, Connection, DataSet, etc.) Please e-mail or PM me if I can be of further help.
-
I did not include the dll in the zip file. Try compiling the project and checking object browser. Does MultiCombo show up in the MultiItemCombo namespace? Are the traditional looking MultiCombo hooks in the WindowsForms generated code section? Finally, yes, the MultiCombo.cs is the code to the control.
-
I'm still hoping for some feedback. This is also a useful control if anyone wants to use it.
-
Please help me by commenting on this project! This is a demonstration project intended to prove a concept. It is a combo box control that can be data bound to multiple fields of a data source, unlike the standard combo box that can be bound to a single field only. So instead of a list that reads: Jimmy Ronald George The list could read: Carter, Jimmy Reagan, Ronald Bush, George What I am most concerned about and what I most want feedback on is my approach for overriding the data binding of the base control. The basic approach is that when binding to a data source, I pull the required information from the data source, format it as I want, and then store it into the base ComboBox�s ObjectCollection (Items property). So the MultiCombo control might be bound to a data source, but the inner base ComboBox is not � the ObjectCollection is exclusively manipulated by the MultiCombo. Although I am handling the IBbindingList and CurrencyManager objects directly, I am worried that somehow there is still a way that the underlying ComboBox will take a new data source behind my back. This is not an issue in the data bound ListView control examples I�ve seen because the base control is not normally set up for data binding, and therefore, does not have the capability to move to a new data source. But a ComboBox does. Please see the larger discussion on this in the comments of the MultiComb.cs class. Please also read the ReadMe text file to get the data base working right in the test application. In addition to data binding, this also demonstrates using property descriptors and reflection, design-time property support and property editors. Thanks. multiitemcombo.zip
-
I want to know where I can find some documentation on the DataMemberListEditor. MSDN has nothing to say about it and a google search only turns up some examples of how to use it. In addition, I want to know what control it uses for its EditValue method. That is, when you click on a property that uses this editor, the Display Member property of a ComboBox for example, it displays a small square with all available database tables and fields. This box is a control and I can't find what control it is. I hope that I can make use of it. My goal is I want to implement a property editor simiar to the DataMemberListEditor. And before I go reinventing the wheel, I want to find out if I can base my work off of this editor but I can't find *any* data on it. Thanks.
-
Don't know of an automatic way but you could try: 1) Use the DataTable.ColumnChanged event to make a list of only the changed items. 2) Duplicate your original table and compare it to the new table. Good luck.
-
I am developing a data bound control and am trying to handle the IBindingList.ListChanged event. Originally, my control's constructor had MyBindingList.ListChange += new ListChangedEventHandler(MyBindingList_ListChanged); But the compiler didn't like it because when the control instance is first created, MyBindingList is null because it hasn't been assigned yet, and might not be for some time, or never if the user doesn't use data binding. So I presume that I need to move my event wiring to the method that detects if my data source supports IBindingList. If the data source does, then wire the event. If it doesn't, then unwire the event. Question #1: Am I on the right track? Question #2: If so, how do I unwire an event? The compiler didn't like MyBindingList.ListChanged =- ListChangedEventHandler; or variations on that theme. object MyDataSource; // Assigned elsewhere. IBindingList MyBindingList; private void AssociateBindingList() { if (MyDataSource is IBindingList) { MyBindingList = (IBindingList)MyDataSource; MyBindingList.ListChanged += new ListChangedEventHandler(MyBindingList_ListChanged); } else { // Unwire old event if necessary somehow // HELP!!!!!!! MyBindingList = null; } } private void MyBindingList_ListChanged(object sender, ListChangedEventArgs e) { // Refresh data } Suggestions? Pointers? Thanks.
-
Okay, so if I understand your scenario correctly, you're talking about something like this: There is an abstract data class that would contain connections, data adapters, command objects etc that provide the basic machinary for connecting to the database. A set of properties to hold settings like what DB to connect to, connection strings, SQL statements, etc., that will all be set at run time by consumers of this class. I would then create a couple of additional business classes that would inherit the data class, and would fine-tune the operations of the data class as appropriate for my project. For example, a set of different methods, each of which returns a different dataset representing a different table in the underlying DB. I would then instantiate a boat load (that's a technical term :D) of these business object whereever I might need them. A specific dataset might be retrieved by something like: // Inside of a WinForms somewhere... MyBusinessClass mbc = new MyBusinessClass(); // This will create a new instance of my business class DataSet authorTable = mbc.GetAuthors(); // Inside the GetAuthors method, a SQL statement and // connection string are built and passed to a GetDataset // method of the data class, which will create a connection // and data adapter, retrieve the data set and pass it // along. The connection and data adapter are destroyed // and the dataset is returned here. Is that about right?
-
Well, while looking up something else I stumbled accross the answer to this. This functionality is implemented through design-time services.