Member 11856456 Ответов: 1

Не удается получить элементы и столбцы для отображения listview


На данный момент я получаю listview, чтобы появиться, однако, ничего не появляется в listview. Это странно, потому что я могу видеть элементы и столбцы, отображаемые в предварительном запуске listview. После того, как программа работает в ListView остается пустым.

Вот код, который я использую:

Вот элемент управления listview, который создается:

Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
Namespace ListViewEmbeddedControls
    Public Class ListViewEx
        Inherits ListView

        <DllImport("user32.dll")>
        Private Shared Function SendMessage(hWnd As IntPtr, msg As Integer, wPar As IntPtr, lPar As IntPtr) As IntPtr
        End Function
        Private Const LVM_FIRST As Integer = &H1000
        Private Const LVM_GETCOLUMNORDERARRAY As Integer = (LVM_FIRST + 59)
        Private Const WM_PAINT As Integer = &HF
        Private Structure EmbeddedControl
            Public Control As Control
            Public Column As Integer
            Public Row As Integer
            Public Dock As DockStyle
            Public Item As ListViewItem
        End Structure
        Private _embeddedControls As New ArrayList()
        Protected Function GetColumnOrder() As Integer()
            Dim lPar As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(GetType(Integer)) * Columns.Count)
            Dim res As IntPtr = SendMessage(Handle, LVM_GETCOLUMNORDERARRAY, New IntPtr(Columns.Count), lPar)
            If res.ToInt32() = 0 Then
                Marshal.FreeHGlobal(lPar)
                Return Nothing
            End If
            Dim order As Integer() = New Integer(Columns.Count) {}
            Marshal.Copy(lPar, order, 0, Columns.Count)
            Marshal.FreeHGlobal(lPar)
            Return order
        End Function
        Protected Function GetSubItemBounds(Item As ListViewItem, SubItem As Integer) As Rectangle
            Dim subItemRect As Rectangle = Rectangle.Empty
            If Item Is Nothing Then
                Throw New ArgumentNullException("Item")
            End If
            Dim order As Integer() = GetColumnOrder()
            If order Is Nothing Then
                Return subItemRect
            End If
            If SubItem >= order.Length Then
                Throw New IndexOutOfRangeException("SubItem " + SubItem + " out of range")
            End If
            Dim lviBounds As Rectangle = Item.GetBounds(ItemBoundsPortion.Entire)
            Dim subItemX As Integer = lviBounds.Left
            Dim col As ColumnHeader
            Dim i As Integer
            i = 0
            While i < order.Length
                col = Me.Columns(order(i))
                If col.Index = SubItem Then
                    Exit While
                End If
                subItemX += col.Width
                System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)
            End While
            subItemRect = New Rectangle(subItemX, lviBounds.Top, Me.Columns(order(i)).Width, lviBounds.Height)
            Return subItemRect
        End Function
        Public Sub AddEmbeddedControl(c As Control, col As Integer, row As Integer)
            AddEmbeddedControl(c, col, row, DockStyle.Fill)
        End Sub
        Public Sub AddEmbeddedControl(c As Control, col As Integer, row As Integer, dock As DockStyle)
            If c Is Nothing Then
                Throw New ArgumentNullException()
            End If
            If col >= Columns.Count OrElse row >= Items.Count Then
                Throw New ArgumentOutOfRangeException()
            End If
            Dim ec As EmbeddedControl
            ec.Control = c
            ec.Column = col
            ec.Row = row
            ec.Dock = dock
            ec.Item = Items(row)
            _embeddedControls.Add(ec)
            Me.Controls.Add(c)
        End Sub
        Public Function GetEmbeddedControl(col As Integer, row As Integer) As Control
            For Each ec As EmbeddedControl In _embeddedControls
                If ec.Row = row AndAlso ec.Column = col Then
                    Return ec.Control
                End If
            Next
            Return Nothing
        End Function
        Protected Overloads Overrides Sub WndProc(ByRef m As Message)
            Select Case m.Msg
                Case WM_PAINT
                    If View <> View.Details Then
                        Exit Select
                    End If
                    For Each ec As EmbeddedControl In _embeddedControls
                        Dim rc As Rectangle = Me.GetSubItemBounds(ec.Item, ec.Column)
                        If (Me.HeaderStyle <> ColumnHeaderStyle.None) AndAlso (rc.Top < Me.Font.Height) Then
                            ec.Control.Visible = False
                            Continue For
                        Else
                            ec.Control.Visible = True
                        End If
                        Select Case ec.Dock
                            Case DockStyle.Fill
                                Exit Select
                            Case DockStyle.Top
                                rc.Height = ec.Control.Height
                                Exit Select
                            Case DockStyle.Left
                                rc.Width = ec.Control.Width
                                Exit Select
                            Case DockStyle.Bottom
                                rc.Offset(0, rc.Height - ec.Control.Height)
                                rc.Height = ec.Control.Height
                                Exit Select
                            Case DockStyle.Right
                                rc.Offset(rc.Width - ec.Control.Width, 0)
                                rc.Width = ec.Control.Width
                                Exit Select
                            Case DockStyle.None
                                rc.Size = ec.Control.Size
                                Exit Select
                        End Select
                        ec.Control.Bounds = rc
                    Next
                    Exit Select
            End Select
            MyBase.WndProc(m)
        End Sub
    End Class
End Namespace




Вот что появляется в форме, когда элемент управления перетаскивается в форму:

Imports System
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Data
Namespace ListViewEmbeddedControls
    Public Class Form1
        Inherits System.Windows.Forms.Form
        Private components As System.ComponentModel.IContainer

        Public Sub New()
            InitializeComponent()
        End Sub
        Protected Overloads Overrides Sub Dispose(disposing As Boolean)
            If disposing Then
                If components Is Nothing Then
                    components.Dispose()
                End If
            End If
            MyBase.Dispose(disposing)
        End Sub
        Private Sub InitializeComponent()
            Dim ListViewGroup1 As System.Windows.Forms.ListViewGroup = New System.Windows.Forms.ListViewGroup("personal", System.Windows.Forms.HorizontalAlignment.Left)
            Dim ListViewItem1 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item1")
            Dim ListViewItem2 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item2")
            Dim ListViewItem3 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item3")
            Dim ListViewItem4 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item4")
            Dim ListViewItem5 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item5")
            Dim ListViewItem6 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item6")
            Dim ListViewItem7 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item7")
            Dim ListViewItem8 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item8")
            Dim ListViewItem9 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item1")
            Dim ListViewItem10 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item2")
            Dim ListViewItem11 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item3")
            Dim ListViewItem12 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item4")
            Dim ListViewItem13 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item5")
            Dim ListViewItem14 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item6")
            Dim ListViewItem15 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item7")
            Dim ListViewItem16 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem("Item8")
            Me.listview1 = New listviewcreatedcontrols.ListViewEmbeddedControls.ListViewEx()
            Me.columnHeader1 = CType(New System.Windows.Forms.ColumnHeader(), System.Windows.Forms.ColumnHeader)
            Me.columnHeader2 = CType(New System.Windows.Forms.ColumnHeader(), System.Windows.Forms.ColumnHeader)
            Me.SuspendLayout()
            '
            'listview1
            '
            Me.listview1.AllowColumnReorder = True
            Me.listview1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
            Or System.Windows.Forms.AnchorStyles.Left) _
            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
            Me.listview1.Columns.AddRange(New System.Windows.Forms.ColumnHeader() {Me.columnHeader1, Me.columnHeader2})
            Me.listview1.FullRowSelect = True
            Me.listview1.GridLines = True
            ListViewGroup1.Header = "personal"
            ListViewGroup1.Name = "Personal"
            Me.listview1.Groups.AddRange(New System.Windows.Forms.ListViewGroup() {ListViewGroup1})
            Me.listview1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None
            Me.listview1.HideSelection = False
            Me.listview1.HoverSelection = False
            Me.listview1.Items.AddRange(New System.Windows.Forms.ListViewItem() {ListViewItem1, ListViewItem2, ListViewItem3, ListViewItem4, ListViewItem5, ListViewItem6, ListViewItem7, ListViewItem8, ListViewItem9, ListViewItem10, ListViewItem11, ListViewItem12, ListViewItem13, ListViewItem14, ListViewItem15, ListViewItem16})
            Me.listview1.LabelWrap = False
            Me.listview1.Location = New System.Drawing.Point(16, 32)
            Me.listview1.MultiSelect = False
            Me.listview1.Name = "listview1"
            Me.listview1.OwnerDraw = True
            Me.listview1.Size = New System.Drawing.Size(368, 240)
            Me.listview1.TabIndex = 0
            Me.listview1.UseCompatibleStateImageBehavior = False
            Me.listview1.View = System.Windows.Forms.View.Details
            '
            'columnHeader1
            '
            Me.columnHeader1.Text = "ColumnHeader1"
            Me.columnHeader1.Width = 119
            '
            'columnHeader2
            '
            Me.columnHeader2.Text = "ColumnHeader2"
            Me.columnHeader2.Width = 124
            '
            'Form1
            '
            Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
            Me.ClientSize = New System.Drawing.Size(400, 302)
            Me.Controls.Add(Me.listview1)
            Me.Name = "Form1"
            Me.Text = "Sample for Controls embedded in a ListView"
            Me.ResumeLayout(False)

        End Sub
        <STAThread>
        Shared Sub Main()
            Application.EnableVisualStyles()
            Application.Run(New Form1())
        End Sub

        Private WithEvents columnHeader1 As ColumnHeader
        Private WithEvents columnHeader2 As ColumnHeader
        Friend WithEvents ListViewEx As ListViewEx
        Private listview1 As ListViewEx

        Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles MyBase.Load

            Dim cb As New ComboBox()
            cb.Text = "tryme"
            listview1.AddEmbeddedControl(cb, 0, 4)

            For I = 0 To listview1.Items.Count - 1
                listview1.Items.Item(I).SubItems.Add("")
            Next

        End Sub

    End Class

End Namespace


Как уже говорилось выше, я подумал, что вполне возможно, что что-то в классе мешает производству предметов. Вот почему изначально я просто разместил этот класс.

Что я уже пробовал:

Я попытался реализовать фазу загрузки с помощью элементов. Однако, если есть способ загрузить элементы в фактический класс, это может помочь.

Richard MacCutchan

Вы объявили свой ListView нарисованным владельцем; где находится обработчик событий OwnerDraw? Откровенно говоря, это выглядит слишком сложным, чтобы просто создать listview с 16 фиксированными строками.

Member 11856456

Ричард, я не возражаю. Однако цель состоит в том, чтобы иметь возможность вставлять и удалять элементы управления, нажав на элемент listview. Однако, поскольку listview не появляется, я понятия не имею, будет ли часть кода встраивания работать правильно, и даже если это произойдет, мне все равно нужен способ удалить встроенный элемент управления, как только я закончу.

Richard MacCutchan

Тогда вы должны забыть о встраивании и получить базовое представление списка, работающее. То, что вы можете сделать с помощью всего лишь нескольких щелчков мыши в конструкторе.

Member 11856456

Может быть, я смогу использовать обычный listview. Есть ли способ встраивать и удалять встроенные элементы управления без создания пользовательского listview?

Richard MacCutchan

К сожалению, это не то, что я когда-либо пытался сделать.

Member 11856456

Я обнаружил, что изменение кода моего класса на 64x исправит эту проблему. Однако по какой-то странной причине код не будет работать в среде 64x.

1 Ответов

Рейтинг:
0

Wendelius

Не знаю, почему у вас есть основной метод внутри формы. Перейдите в Настройки Приложения и проверьте, что такое настройка в нем Startup form.

Кроме того, поместите несколько точек останова, чтобы увидеть, действительно ли ваш код инициализации поражен.


Member 11856456

Мне пришлось пересмотреть код в вопросе. Выяснилось, что он не добавляется в форму, потому что в части кода класса чего-то не хватает. Надеюсь, я смогу получить помощь в понимании того, почему это не работает.

Wendelius

В коде, который вы опубликовали, я не могу найти никаких команд, которые действительно добавляли бы элементы в listview

Member 11856456

Я опубликовал дополнительный код, который появляется после добавления элемента управления в форму. Я должен извиниться, потому что я думал, что это был управляющий код, который мешал мне видеть элементы, появляющиеся во время выполнения. Это очень странно, потому что после запуска программы элементы появляются в элементе управления, и вы можете увидеть их, когда смотрите на форму перед отладкой. Однако после запуска процесса отладки listview становится полностью пустым в форме.

Wendelius

Так вы имеете в виду, что во время отладки вы не можете видеть изменения в listview? Глядя на код, макет приостанавливается, пока добавляются элементы:

Меня.SuspendLayout()

Member 11856456

Я понял, почему это не работает, часть кода основана на приложении 86x, программа, которую я создаю, - это 64x. Я подтвердил это, сделав различные сборки с кодом в новом проекте. Я не знаю, где я могу изменить код класса, чтобы сделать его пригодным для использования в программе 64x.

Wendelius

У вас есть некоторые вызовы системных функций, таких как user32. Лучшее, что я могу предложить, - это сузить проблему, исключив вызовы, чтобы выяснить, какой из них вызывает проблему.

Member 11856456

Я исключил все, кроме 1 одной части, которая относится к 32 битам. вот небольшая часть, для которой мне нужен обходной путь.

Защищен перегрузок переопределяет суб WndProc, который(как byref M как сообщение)
Выберите м случае.Сообщение
Случае сообщения WM_PAINT
Тусклый rc как прямоугольник
Для каждого ec как EmbeddedControl в _embeddedControls
РЦ = меня.GetSubItemBounds(ЕК.Элемент, ЭУ.Колонки)
ЭК.контроль.Границы = rc
Следующий
Выход Выберите
Конец Выбрать
Моя база.WndProc(m)
Конец Подводной Лодки

Мне нужно, чтобы удалить часть краски и М сообщение. Однако я не уверен, как сделать аналогичную защищенную перегрузку, которая будет направлена на остальную часть кода.