Change the image from multiple dynamic picturebox

后端 未结 1 423
粉色の甜心
粉色の甜心 2020-12-22 04:24

I\'m making a contactlist with VB.NET with status images. I\'m loading this list from MSSQL but when i reload the list it flickers.

This list is a TableLayoutPanel w

相关标签:
1条回答
  • 2020-12-22 05:07

    A UserControl is a bit like a subform. It is a container for an assortment of controls which act together or represent some logical unit. In this case, it would be the visual representation of some user states (properties). Rather than creating and managing individual controls, you can put them on one UC and encapsulate much of the code to manage them.

    In the Solution Explorer window, right click, select Add, then pick UserControl. I added a TableLayoutPanel, 2 PictureBoxes and a Label (all with proper names of course). There is also an ImageList with a quick grab of your images:

    This alone replaces many many lines of code you have to create new controls and then setting the same properties over and over again. To make them act as a logical object, you can add properties which abstracts the minutiae of selecting images etc:

    Public Class Chatter
    
        Public Enum ChatStatus
            Unknown
            Online
            Away
            Offline
        End Enum
    
        Public Enum ChatMsgStatus
            Undefined      ' kludge to force the initial state
            Unknown
            [New]
            Read
        End Enum
    
        ' one set of images for all chatter instances
        Private Shared Imgs As Image()
    
        Public Property ChatId As Int32         ' or guid?
    
        Private chName As String = ""
        Public ReadOnly Property ChatName As String
            Get
                Return chName
            End Get
        End Property
    
        Private mStatus As ChatMsgStatus = ChatMsgStatus.Undefined
        Public Property MsgStatus As ChatMsgStatus
            Get
                Return mStatus
            End Get
            Set(value As ChatMsgStatus)
                If (value <> mStatus) Then
                    Select Case value
                        Case ChatMsgStatus.New
                            pbMStatus.Image = Imgs(3) 
                        Case ChatMsgStatus.Read
                            pbMStatus.Image = Imgs(4)
                        Case Else
                            pbMStatus.Image = Imgs(4)
                    End Select
                End If
                mStatus = value
            End Set
        End Property
    
        Private chStatus As ChatStatus = ChatStatus.Unknown
        Public Property Status As ChatStatus
            Get
                Return chStatus
            End Get
            Set(value As ChatStatus)
                If value <> chStatus Then
                    Select Case value
                        Case ChatStatus.Online
                            pbUStatus.Image = Imgs(0)
                        Case ChatStatus.Away
                            pbUStatus.Image = Imgs(1)
                        Case ChatStatus.Offline
                            pbUStatus.Image = Imgs(2)
                        Case Else
                    End Select
                End If
                chStatus = value
            End Set
        End Property
    
        Public Sub New()
            ' This call is required by the designer.
            InitializeComponent()
    
            If Imgs Is Nothing Then
                Imgs = New Image() {My.Resources.ChatUserGrn, My.Resources.ChatUserYlw, 
                   My.Resources.ChatUserRed, My.Resources.ChatBalloonGrn,
                   My.Resources.ChatBalloonGry}
    
                   ' see note
            End If
        End If
            ' Add any initialization after the InitializeComponent() call.
        End Sub
        ' no need to create one without Identifiers
        Public Sub New(n As Int32, cname As String)
            MyClass.New()
            ' default intitial values:
            chName = cname
            ChatId = n
    
            lblChName.Text = cname
            Me.Status = ChatStatus.Online
            Me.MsgStatus = ChatMsgStatus.Unknown
        End Sub
    End Class
    

    (Edit) I didn't like the result using an ImageList. This version, loads an array of images from resources. Aside from only loading one copy of GreenUser for use by all users, it allows you to tailor it as needed. For instance change the backcolor to SystemColors.Window to match the user's theme. If you also use a label instead of a picturebox, you can use the Text property for "?" or even indicate the number of new messages.

    I am sure there is more to it and I can think of several things I would want it to know (for instance overlay the green balloon with the number of unread messages). But the point here are the concepts of encapsulation, DRY and reusable code.

    When you compile it, there will be a new Chatter control in the toolbox. Add some at runtime using the properties exposed:

    Dim c As New Chatter(42, "Ziggy von Hausen")
    flpChat.Controls.Add(c)
    
    c = New Chatter(14, "ThDutoit")
    c.MsgStatus = Chatter.ChatMsgStatus.New
    flpChat.Controls.Add(c)
    
    c = New Chatter(78, "Plutonix")
    c.Status = Chatter.ChatStatus.Offline
    flpChat.Controls.Add(c)
    
    c = New Chatter(4, "Codexer")
    c.MsgStatus = Chatter.ChatMsgStatus.New
    c.Status = Chatter.ChatStatus.Away
    flpChat.Controls.Add(c)
    

    The Id would be something to uniquely identify each chat participant. The name is not usually enough (SO has over 50 pages of people named "Steve") and you will want a way to identify to link a control to a user. (An alternative, would be a ChatterBox reference in the user list which is a reference to the related UserControl:

    Dim user = "Codexer"
    
    Dim chatter = flpChat.Controls.
                OfType(Of Chatter).
                FirstOrDefault(Function(c) c.ChatName.StartsWith(user))
    If chatter IsNot Nothing Then
        chatter.Status = chatter.ChatStatus.Online
    End If
    

    It is sub optimal to search each time and an Id would be better than a mere name. The ideal would be for a ChatUser class with all the other stuff the app has to store by user. The class should include a reference to the control so that when the status changes or whatever, the class could simply:

    myChatterBox.Status = myStatus
    

    Result:

    Certainly they can be created with considerably less code. In the course of things, you can change the status of either image by just setting the related property.

    As an added benefit, because you are no longer creating individual controls, and because UserControl inherits from Component you dont have to worry about leaks if/when these are removed.

    A Must Read:
    Creating a Windows Form User Control

    0 讨论(0)
提交回复
热议问题