Jump to content
Xtreme .Net Talk

rbulph

Avatar/Signature
  • Posts

    398
  • Joined

  • Last visited

Everything posted by rbulph

  1. I've got a List of objects that I need to sort. There's a variety of criteria for the order that I want to sort them into, and for some of them I simply want the existing order to be maintained. For these objects I have no other record of their appropriate order than the order they are contained in in the List, and I want to preserve this. To sort them it seems sensible to use a class implementing IComparer, but the problem is, if I just return 0 for these items that I don't want sorting, they get sorted anyway (I'm not quite sure in accordance with what). So I've solved the problem by making a copy of the List before I do the sort and looking at the position of items in that. But it would be better if I didn't have to make this copy. Can you see a way around this? Here's some simple code so that you can see what I've done: Public Class Form1 Friend p As New List(Of String) Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load p.Add("Mouse") p.Add("Manatee") p.Add("Mole") p.Add("Ant") p.Add("Bee") p.Add("Walrus") p.Add("Monitor Lizard") Dim p2 As New List(Of String) For Each s As String In p p2.Add(s) Next p.Sort(New consorter(p2)) For Each i As String In p Debug.Print(i) Next End Sub Private Class consorter 'A class to sort a List of strings alphabetically, provided that if they begin with the same letter, they remain in the same order as before. Implements Collections.Generic.IComparer(Of String) Private presortlist As List(Of String) Friend Sub New(ByVal p As List(Of String)) presortlist = p End Sub Public Function Compare(ByVal x As String, ByVal y As String) As Integer Implements System.Collections.Generic.IComparer(Of String).Compare If x = y Then Return 0 Dim Dif As Integer = Asc(x.Chars(0)) - Asc(y.Chars(0)) If Dif = 0 Then Return presortlist.IndexOf(x) - presortlist.IndexOf(y) 'if I just return 0 here then the order of things beginning with "M" gets changed. Else Return Dif End If End Function End Class End Class
  2. Possibly. Actually I don't think this is going to work, because there are problems with inheritance. Suppose I have a class "Base", and two classes that inherit directly from that, "Derived1" and "Derived2". If I have two references, x and y to Base class objects, it would be perfectly reasonable to have code to check whether x is y. But if x is in fact a Derived1 object and y a Derived2 object and I send them both to a procedure to check whether the comparison is appropriate, it will look as if it's not, because neither of them inherits from the other. I need a comparison of the types with which x and y are declared, not the types which the objects they refer to are. And I don't see how that can be done. Incidentally, is there a practical difference between Object.ReferenceEquals and Is?
  3. I think that If a.GetType.IsAssignableFrom(b.GetType) Or b.GetType.IsAssignableFrom(a.GetType) Then would be better to use instead of If a.GetType Is b.GetType Then so as to allow for inheritance.
  4. I have 545 occurences of the word "Is" in my project! Probably most are the operator (i.e. not in comments). I have, as an example, a facility for the user to draw a line from one control to another of the same type, using the mouse. If the control that he starts drawing from Is the one that the cursor moves over, then I don't want the line to be drawn. Otherwise I do.
  5. If I use "TypeOf" on an object comparing it to a type that it can never be, I get the error "Expression of type [ ]can never be of type [ ]." That's useful. But if I use "Is" to compare one object against another which is of a type that the first can never be, I don't even get a warning. That's led to a few mistakes, and it would be really helpful if I did get some sort of warning. Is there any alternative to creating a function like "StrongIs" below if I want to get some notice of this sort of mistake? Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim x As Button = Me.Button1 If TypeOf x Is Form Then Beep() 'gives an error If x Is Me Then Beep() 'why can't this give an error? If StrongIs(x, Me) Then Beep() 'Is there any alternative to this? End Sub Friend Function StrongIs(ByVal a As Object, ByVal b As Object) As Boolean If a.GetType Is b.GetType Then Return a Is b Else Err.Raise(1) End If End Function End Class
  6. I suppose I could probably speed it up by just querying the Margins and Bounds once and storing them.
  7. The slowness seems to be the result of this (unrelated) code which is currently called during deserialization and which takes half a second to complete: Private Function PrintingArea() As Rectangle 'Return the area of the paper that printing is to take place on. With PrintDocument1.DefaultPageSettings Return New Rectangle(.Margins.Left, .Margins.Top, .Bounds.Width - .Margins.Left - .Margins.Right, .Bounds.Height - .Margins.Top - .Margins.Bottom) End With End Function Don't know why this should be so slow.
  8. OK, after a break have gone back to this and got it to work, with some help from this article http://www.codeproject.com/KB/vb/serializevbclasses.aspx. Outstanding problems are that it seems to take a lot of processor power to open files now and I have a static variable in one of my procedures that leads to an error sometimes on deserialization (field can't be found). I've now marked this as nonserializable so hopefully that will do the trick.
  9. Problem is, the deserialization creates a ghost Parent to handle the events. Even if I put InitializeComponent in the new New Sub it doesn't seem to get created properly and there are errors when it's constituent controls get referenced. If I try to Serialize the Parent property of Child, and then substitute the deserialized Parent with a new Parent, the problem doesn't go away. Maybe the best solution is to simply remove all the event handling while I'm saving and add it in as soon as I've finished.
  10. Thanks. If I mark Parent as Serializable, implement ISerializable in Parent, adding: Public Sub GetObjectData(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext) Implements System.Runtime.Serialization.ISerializable.GetObjectData End Sub Friend Sub New(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext) InitializeComponent() End Sub so that, although Parent is serializable, nothing gets serialized, the problem seems to be resolved.
  11. When I run the following code I get a message that the Parent class is not marked as serializable. This is very annoying since I'm not trying to serialize the Parent. Is this is a bug in Visual Studio? How do I get around it? Imports System.Runtime.Serialization.Formatters.Binary Imports System.IO Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim FileStream As Stream = File.Create("C:\abc.abc") Dim serializer As New BinaryFormatter With serializer Dim Child1 As New Child Dim Parent1 As Parent = New Parent(Child1) .Serialize(FileStream, Child1) 'Get an error at this line - "Parent... is not marked as Serializable." End With End Sub End Class Public Class Parent Inherits PictureBox 'this is why I can't serialise the Parent class Friend WithEvents MyChild As Child Friend Sub New(ByVal newChild As Child) MyChild = newChild newChild.MyParent = Me End Sub Private Sub ChildNotify() Handles MyChild.InformParent ' End Sub End Class <Serializable()> Public Class Child Event InformParent() <NonSerialized()> Friend MyParent As Parent End Class
  12. That's a good idea, and I hadn't thought of that. But it doesn't answer my question does it? I still have the problem that the ToolStripSplitButton can't be checked. I suppose what I can do is have a ToolStripDropDownButton (which also can't be checked) with no image so that just the dropdown icon shows and have that immediately to the right of a ToolStripButton. Its menus can, as you suggest have the relevant images so it's clear they relate to the ToolStripButton which will always show one of them. Doesn't look too bad.
  13. I have two very similar operations that I want to be made available by selecting a toolbar button. Because they're so similar it seems a waste to have two buttons for them. What would be ideal would be to have a ToolstripSplitButton with two menu items for selecting between the operations. I would change the image on the button slightly to reflect which had been chosen. But the ToostripSplitButton can't be Checked to show that it has been selected. This is so frustrating. Any ideas for other ways to present the options to the user?
  14. Well here's some code which works reasonably well. The main problems outstanding are that (i) the user can't drag the toolbar over a docking position onto the other side. Once it's docked it's stuck, and (ii) the toolbar form doesn't an activated caption. Hopefully this is useful to someone, and if anyone has any suggestions for improvement, I'd be glad to hear them. You will need two forms, Form1 being the startup form. It contains toolstrippanels on each side and a toolstrip. Toolstrippanels don't seem to appear in the toolbox so I had to add them manually with code in the form's designer. Imports System Imports System.Windows.Forms Imports Microsoft.WindowsCE.Forms Public Class Form1 Friend toolbarformsetup As Boolean Dim frmToolbar As Form2 Private Sub ToolStrip1_EndDrag(ByVal sender As Object, ByVal e As System.EventArgs) Handles ToolStrip1.EndDrag Dim InPanel As Boolean For Each c As Control In Me.Controls If TypeOf c Is ToolStripPanel Then If c.Bounds.Contains(Me.PointToClient(MousePosition)) Then InPanel = True End If Next If Not InPanel Then tspTop.Controls.Remove(Me.ToolStrip1) frmToolbar = New Form2 frmToolbar.Controls.Add(Me.ToolStrip1) ToolStrip1.Location = New Point(0, 0) ToolStrip1.GripStyle = ToolStripGripStyle.Hidden frmToolbar.Show(Me) frmToolbar.Location = MousePosition toolbarformsetup = True frmToolbar.Activate() End If End Sub Friend Sub ReviewToolbar() Dim p As Point = PointToClient(MousePosition) Dim border As Integer = (Width - ClientSize.Width) / 2 Dim ClientTop As Integer = Height - ClientSize.Height - border If toolbarformsetup And Me.Bounds.Contains(MousePosition) Then Dim RelTSP As ToolStripPanel = Nothing Dim ThinDimension As Integer = Math.Min(ToolStrip1.Width, ToolStrip1.Height) If p.Y > ClientTop And p.Y < ClientTop + ThinDimension Then RelTSP = Me.tspTop ElseIf p.Y > Height - border - ThinDimension Then RelTSP = Me.tspBottom ElseIf p.X < border + ThinDimension Then RelTSP = Me.tspLeft ElseIf p.X > Width - border - ThinDimension Then RelTSP = Me.tspRight End If If Not RelTSP Is Nothing Then frmToolbar.Controls.Remove(ToolStrip1) RelTSP.Join(ToolStrip1) ToolStrip1.GripStyle = ToolStripGripStyle.Visible If RelTSP Is Me.tspTop Or RelTSP Is Me.tspBottom Then ToolStrip1.Left = p.X - border Else ToolStrip1.Top = p.Y - ClientTop End If Activate() frmToolbar.Close() toolbarformsetup = False End If End If End Sub 'I want to have the toolbar show an active caption at the same time as the main form, but I haven't been successful in 'getting this to work. 'Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal n As Long, ByVal w As Long, ByVal k As Long) As Long Const WM_NCACTIVATE = &H86 'Private Sub Form1_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Activated ' ' Dim msg As System.Windows.Forms.Message = _ ' If Not p Is Nothing Then ' SendMessage(p.Handle.ToInt32, WM_NCACTIVATE, 1, 0) ' ' Dim msg As Microsoft.WindowsCE.Forms.Message = Microsoft.WindowsCE.Forms.Message.Create(p.Handle.ToInt32, _ ' ' &H86, 1, 0) ', New IntPtr(e.X), New IntPtr(e.Y)) ' ' Microsoft.WindowsCE.Forms.MessageWindow.SendMessage(msg) ' End If 'End Sub End Class Public Class Form2 'form must be TopMost, fixed toolwindow, autosize grow and shrink and have no maximise button (it won't show, but double-clicking will maximise it) 'nor have minimize button nor show in toolbar. Private Sub Form2_Move(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Move Form1.ReviewToolbar() End Sub End Class
  15. Anyone figured out how to provide a floating toolbar in conjunction with ToolStripPanels? I'm using four ToolStripPanels rather than a ToolStripContainer because it's an MDI form and the ToolStripContainer doesn't seem to allow the display of MDI children.
  16. Actually "I could set the width of the rectangle to be the same as the width required for the longest word in the text but that still doesn't guarantee that other words won't be broken up on other lines." is wrong. As long as the box is wide enough for the longest word, other words won't be wrapped across lines. So that reduces the problem to just finding the longest word in the string, which is not too hard. Any thoughts still welcome though.
  17. I want to draw some text to the side of a vertical line. The text could be anything. The vertical line has a limited length. According to this link ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.en/CPref17/html/T_System_Windows_Forms_TextRenderer.htm "The DrawText methods of TextRenderer are not supported for printing. You should always use the DrawString methods of the Graphics class." I want to use the same procedure both on screen and for printing, so it seems I should use the DrawString methods, not the TextRenderer. I don't want the text to appear on just one line if it consists of more than one word, as it could then be too wide. I'd like it to appear on as many lines as possible within the vertical extent of the line. So I could draw the text with DrawString, setting a layoutRectangle parameter. The rectangle could be as high as the line is long. But I don't want it to be too wide or all of the text will be on one line. Moreover I want to ensure that no words are wrapped across lines. There doesn't seem to be any easy way to achieve this. I could set the width of the rectangle to be the same as the width required for the longest word in the text but that still doesn't guarantee that other words won't be broken up on other lines. I suppose I could analyse the space required for each word in the text and work from there, but that seems very laborious. Or maybe I could use a hidden richtext box. That won't break words up, so I could just adjust that as necessary and copy its size. So any suggestions before I leap into this?
  18. Have given up on using the dragdrop capability and am just capturing the mouse with my form to check where it comes up again. I have to reproduce the dragdrop cursor, but otherwise it's not too much trouble.
  19. If the user begins a dragdrop operation, and then cancels it, either by dropping on an irrelevant part of the screen or by pressing the Esc key, how can I detect that this has happened?
  20. Thanks. I'm only doing this once, with four class types, so the repetition isn't really a problem. It's just become a bit instinctive to try to cut out repetition where I see it...
  21. Working on the basis that all repetition is bad, is there a good way to write code to call constructors for a range of class types all deriving from a common base? e.g. Dim h As base If x = 0 Then h = New base(1, "ABC") ElseIf x < 0 Then h = New inheritor1(1, "ABC") ElseIf x > 0 Then h = New inheritor2(1, "ABC") End If Public Class base Public Sub New(ByVal x As Long, ByVal y As String) End Sub End Class Public Class inheritor1 Inherits base Public Sub New(ByVal x As Long, ByVal y As String) MyBase.New(x, y) End Sub End Class Public Class inheritor2 Inherits base Public Sub New(ByVal x As Long, ByVal y As String) MyBase.New(x, y) End Sub End Class I know you can use Activator.CreateInstance but then there's no check on whether the array that you're sending to the constructor is valid until runtime. So any thoughts?
  22. Thanks, that solves it. Don't know why they have to have a MouseDoubleClick event as well as a DoubleClickEvent.
  23. I'd like to know when the user double-clicks on the gripper part of a toolbar. I can use the toolbar's doubleclick event but this only passes e as System.EventArgs, which doesn't contain the location where the user double-clicked. If he double-clicks on a disabled button then this event triggers as well, so the two actions seem to be indistinguishable. Any ideas how to just capture a double-click just on the gripper part of the toolbar?
  24. rbulph

    Generics

    Yes, I think so. I far prefer that to chucking everything into one big bag and having to do iterations to find the things that I need in it. If it inherits List(Of BasicLine) (say) then I'm not distinguishing between LineCols that contain CurvedLines and ones that contain StraightLines. If it inherits CollectionBase and is a generic (Of BasicLine) then I can set it up to contain only CurvedLines or StraightLines when I declare it. If I have the LineCols, I don't think it would be, because then it's duplicative to store this information with each BasicLine. As I say, there are plenty of ways to work around the issue. Looks as if I have to do so to some extent.
  25. rbulph

    Generics

×
×
  • Create New...