1

我有一个非常简单的类,它包含一些公共属性——ID、文本、颜色等和一个名为“SelectedItem”的布尔值。就像CheckedRadioButtons 上的属性一样,只有一个项目可以将其SelectedItem属性设置为True特定组内。注意:将有几个单独的组(列表),每个组只能有一个带有SelectedItem = True.

我的第一个想法是,我可能只需要处理班级以外的所有内容,在选择其他项目时为特定列表中的所有其他项目SelectedItem设置。False但这对我来说似乎相当不雅。所以我一直在努力思考如何课堂上做到这一点。例如:我是否可以有一个名为“GroupName”的私有字符串属性 - 在New添加类的新实例时在子中设置 - 然后使用私有共享方法将每个项目的SelectedItem属性设置为False前提是项目具有相同GroupName作为新选择的项目?我会尝试这样做,但我不知道如何从该类中枚举该类的每个实例,或者这是否可能。是吗?还是有另一种(更好的)方法来实现我的目标?


编辑

感谢所有的建议和意见,他们都非常感谢。

根据 Tim 和 Cyborgx37 的评论,我决定听从他们的建议并使用 CollectionBase 作为项目管理器类。这是我到目前为止所拥有的精简版:

Public Class ResourceItem
    Public ID As Integer
    Public Text As String
    Public SelectedItem As Boolean
End Class

Public Class ResourceItemsManager
    Inherits System.Collections.CollectionBase

    Public Sub Add(ByVal iID As Integer, ByVal sText As String)
        Dim newResItem As New ResourceItem
        With newResItem
            .ID = iID
            .Text = sText
        End With
        List.Add(newResItem)
    End Sub

    Default Public ReadOnly Property Item(ByVal Index As Integer) As ResourceItem
        Get
            If Index < Count And Index >= 0 Then
                Return CType(List.Item(Index), ResourceItem)
            Else
                Return Nothing
            End If
        End Get
    End Property

    Public Sub ClearAll()
        List.Clear()
    End Sub

    Public Sub SelectItem(ByVal Index As Integer)
        If Index < Count And Index >= 0 Then
            For i As Integer = 0 To List.Count - 1
                List.Item(i).SelectedItem = i = Index
            Next
        Else
            'Exception code here
        End If
    End Sub
End Class

可以看出:我没有实例化一个 newResourceItem并将其作为参数传递给管理器的Add过程,而是简单地传递了新项目的详细信息,并且该过程正在从中创建项目。我不知道这是个好主意还是坏主意-请告知-但我已经这样做了,因为我不知道如何使 SelectedItem 属性只能由经理写入,所以我想避免直接访问可以将其SelectedItem属性设置为的对象,True而无需取消选择同一组中的所有其他项目。当然,仍然有可能将变量设置为经理的列表项之一并从那里进行设置,所以我仍然想知道如果可能的话,我该如何防止这种情况发生。


更新
最后我没有使用上面的代码,而是决定使用 Cyborgx37 的解决方案——尽管有关于最佳实践的警告,这似乎对我来说效果很好。我还意识到我需要在另一个可以选择多个项目的场景中使用同一个类因此很容易向管理器添加一个布尔属性来启用它。

4

2 回答 2

1

这是一个非常简单的解决方案。它并不遵循所有最佳实践(例如,在 ItemManager 中公开 Items 集合可能是一个坏主意),但它展示了中央管理器的想法以及与管理器交互的各个项目中的属性。

Module Module1

Sub Main()

    Dim l_itemManager As New ItemsManager()

    Dim l_item1 As New Item(l_itemManager) With {.Description = "Item 1"}
    Dim l_item2 As New Item(l_itemManager) With {.Description = "Item 2"}
    Dim l_item3 As New Item(l_itemManager) With {.Description = "Item 3"}
    Dim l_item4 As New Item(l_itemManager) With {.Description = "Item 4"}

    l_itemManager.SelectedItem = l_item1

    Console.WriteLine("Item 1 = " & If(l_item1.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("Item 2 = " & If(l_item2.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("Item 3 = " & If(l_item3.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("Item 4 = " & If(l_item4.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("")

    l_itemManager.SelectedItem = l_item2

    Console.WriteLine("Item 1 = " & If(l_item1.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("Item 2 = " & If(l_item2.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("Item 3 = " & If(l_item3.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("Item 4 = " & If(l_item4.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("")

    l_item3.IsSelected = True

    Console.WriteLine("Item 1 = " & If(l_item1.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("Item 2 = " & If(l_item2.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("Item 3 = " & If(l_item3.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("Item 4 = " & If(l_item4.IsSelected, "Selected", "Unselected"))
    Console.WriteLine("")

    Console.WriteLine("Press any key...")
    Console.ReadKey(True)

End Sub

Class ItemsManager

    Public Event SelectedItemChanged As EventHandler

    Public Items As New List(Of Item)

    Private _item As Item
    Public Property SelectedItem() As Item
        Get
            Return _item
        End Get
        Set(ByVal value As Item)
            _item = value
            RaiseEvent SelectedItemChanged(sender:=Me, e:=EventArgs.Empty)
        End Set
    End Property

End Class

Class Item

    Public Event IsSelectedChanged As EventHandler

    Private WithEvents _manager As ItemsManager
    Public ReadOnly Property Manager() As ItemsManager
        Get
            Return _manager
        End Get
    End Property

    Private _description As String
    Public Property Description() As String
        Get
            Return _description
        End Get
        Set(ByVal value As String)
            _description = value
        End Set
    End Property

    Public Property IsSelected() As Boolean
        Get
            Return Me.Manager.SelectedItem Is Me
        End Get
        Set(ByVal value As Boolean)
            If value Then
                Me.Manager.SelectedItem = Me
            Else
                Me.Manager.SelectedItem = Nothing
            End If
        End Set
    End Property

    Public Sub New(ByVal manager As ItemsManager)
        _manager = manager
        Me.Manager.Items.Add(Me)
    End Sub

    Private Sub _manager_SelectedItemChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles _manager.SelectedItemChanged
        RaiseEvent IsSelectedChanged(sender:=Me, e:=EventArgs.Empty)
    End Sub

End Class

End Module

编辑:

虽然不完全符合最佳实践,但此代码将起作用。最佳实践高度依赖于上下文,因此在不了解应用程序细节的情况下很难说出“正确”的方法是什么。也就是说,管理器和子类的一般概念(子类调用管理器以获取它们的状态)应该在几乎所有情况下都有效。

我同意@TimSchmelter,CollectionBase 会给你最大的权力。但是你可能不需要那么多的力量来达到你的目的。而且你最终仍然不得不使用类似于我发布的代码 - 孩子们会向父母询问他们的状态。

注意:我纠正了上面代码中的一个小错误。将选定项目设置为未选定将不会导致任何事情发生。我已更改此行为以使 SelectedItem 为空。

于 2012-06-01T17:31:19.937 回答
1

您可以将集合传递给 ctor 中的类并在那里迭代列表。

   List<People> peoples = new List<people>();
   peoples.add(new People("Group1", peoples));
   peoples.add(new People("Group1", peoples));
   peoples.add(new People("Group1", peoples));


   Public Class People, iNotifyPropertyChanged
   {
      private List<People> peoples;
      private bool isChecked = false;

      public book IsChecked 
      { 
          get { return isChecked; }
          set 
          {
              if(isChecked = value) return;
              isChecked = value;
              if (isChecked)
              {
                  foreach (person p in peoples)
                  {
                      if (p.Ischecked && p != this)  p.Uncheck();
                  }
              }
          }
      }
      public void Uncheck
      {
          isChecked = false;
          NotifyPropertyChanged("IsChecked");
      }

      public People(string group, List<People> _peoples { peoples = _peoples; };
   }
于 2012-06-01T18:07:47.427 回答