【问题标题】:C# Pointing to a List<T> (WinForms)C# 指向列表<T> (WinForms)
【发布时间】:2014-01-21 15:32:54
【问题描述】:

我一直想知道如何正确地做到这一点,但我并不完全确定。

我想创建一个用户名列表并使用 foreach 循环将用户名绘制到屏幕上。用户名列表是一个静态列表,将保存在 MainClass 中,绘制过程将发生在另一个类中(对于这种情况,我们将其称为 Printer 类)。

我的“问题”是我想要做到这一点,以便我不只是将该列表从 MainClass 复制到一个单独的列表到打印机类中,所以当我从列表中添加/删除一个对象时,打印机类可以立即看出它已经改变了。

编辑:我不太需要担心列表更改的事件,因为列表将在 Paint 事件上打印。我主要需要在 Printer 类中创建一个新变量,并在类首次初始化时将该变量与相关列表“链接”

我不能简单地在 Printer 中使用 MainClass.usernameList,因为它会同时用于多个列表,复制 MainClass 列表只会为我提供一个永远不会更新的列表(除非我告诉它,但这可能会变得乏味有许多同时上课)。

我假设我需要使用指针,但我以前从未使用过它们,整个 Unsafe 代码的想法似乎......不安全。

总结: 我需要在一个公共类中创建一个指向另一个类中的静态列表的变量。

代码很邋遢,但希望人们能更好地了解我想要实现的目标:

【问题讨论】:

  • 您想通过binding to an ObservableCollection 执行此操作。此外,除非出于某些已知原因,否则不要将 WinForms 用于新项目。 WPF 是更现代的框架,例如数据绑定从第一天开始就是设计的一部分,而不是事后才想到的。
  • 我会以不同的方式解决您的问题,定义一个新类 MyList 并添加将在使用函数 Additem 将新项目添加到列表时触发的事件,这样你会知道您的列表中何时添加/更改了某些内容
  • 您不需要不安全的代码或指针,您只需要在您的 GUI 对象之间共享对 ObservableCollection(或其他一些数据源)的引用。请记住,在 C# 中传递一个对象(不是值类型)并复制它。
  • @JafarKofahi 这就是ObservableCollection 已经在做的事情。没有必要重新实现它
  • @millimoose 感谢您指出我不知道 ObservableCollection 直到你们提到它。

标签: c# list pointers


【解决方案1】:

我认为你的问题不应该按照你的方式解决;无论如何,如果您使用 ObservableCollection,您可以在从列表中添加和删除元素时收到通知,然后您可以做出反应。

此外,如果您的列表是静态的,则不需要传递引用,但如果这样做,您仍然引用同一个对象,因此您始终拥有更新的列表。

【讨论】:

    【解决方案2】:

    您可以将列表设为ObservableCollection&lt;T&gt;,然后在绑定到您集合的CollectionChanged 事件的其他类中实现逻辑。

    因此,您只需将您的集合存储在任何有用的地方,然后在帮助类或控件或任何您需要的地方实现CollectionChanged 事件的事件处理程序。每当集合的内容发生变化时,都会调用事件处理程序:

    myCollection.CollectionChanged += SomeHelperClass.OnCollectionChanged;
    

    在你的助手类中你写

    public void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // process e.NewItems
        ...
    
        // process e.OldItems
        ...
    }
    

    另见http://msdn.microsoft.com/en-us/library/ms668604(v=vs.110).aspx

    【讨论】:

    • 值得记住的是,将事件处理程序从 Printer 类添加到静态列表将导致内存/引用泄漏。因此,在卸载打印机表单时必须删除事件处理程序。
    • @RononDex:这个答案满足了 OP 的要求,而你的却没有……正如 OP 所指出的,有必要对列表中的变化做出响应。
    【解决方案3】:

    您不需要为此使用 unsafe 块。所有对象都是默认引用,内容不会被复制。

    var x = new List<int>() { 1, 2, 3 };
    
    var printer = new Printer();
    
    // this assignment does not copy the list - it assigns the property to the same list
    printer.UserList = x;
    
    // verify that the reference was copied, not the data
    x.Add(4);
    printer.UserList.Add(5);
    
    MessageBox.Show(x.Count.ToString()); // shows 5
    MessageBox.Show(printer.UserList.Count.ToString()); // also shows 5
    

    这是classstruct 之间的主要区别。如果你有一个struct,那么它将被复制它的所有整数、DateTime 等变量。

    【讨论】:

      【解决方案4】:

      我没有看到有人用一种方法来回答你的List&lt;T&gt;中发生的事情。

      为此,您将为您的列表创建一个基本的小包装器,其中至少包含一个您需要连接的 EventHandler 对象。

      这是我刚刚汇总的一个非常基本的实现:

      public class SubscribeList<T> : IList<T> {
      
        private List<T> list;
      
        public EventHandler OnListContentsChange;
      
        public SubscribeList() {
          list = new List<T>();
        }
      
        public int IndexOf(T item) {
          return list.IndexOf(item);
        }
      
        public void Insert(int index, T item) {
          list.Insert(index, item);
          OnListContentsChange(this, EventArgs.Empty);
        }
      
        public void RemoveAt(int index) {
          list.RemoveAt(index);
          OnListContentsChange(this, EventArgs.Empty);
        }
      
        public T this[int index] {
          get {
            throw new NotImplementedException(); // do this if you want,
          }
          set {
            throw new NotImplementedException(); // but it is more complicated
          }
        }
      
        public void Add(T item) {
          list.Add(item);
          OnListContentsChange(this, EventArgs.Empty);
        }
      
        public void Clear() {
          list.Clear();
          OnListContentsChange(this, EventArgs.Empty);
        }
      
        public bool Contains(T item) {
          return list.Contains(item);
        }
      
        public void CopyTo(T[] array, int arrayIndex) {
          list.CopyTo(array, arrayIndex);
          OnListContentsChange(this, EventArgs.Empty);
        }
      
        public int Count {
          get { return list.Count; }
        }
      
        public bool IsReadOnly {
          get { return false; }
        }
      
        public bool Remove(T item) {
          var ok = list.Remove(item);
          if (ok) {
            OnListContentsChange(this, EventArgs.Empty);
          }
          return ok;
        }
      
        public IEnumerator<T> GetEnumerator() {
          foreach (var item in list) yield return item;
        }
      
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
          return list.GetEnumerator();
        }
      }
      

      现在,你是这么说的:

      总结:我需要在一个公共类中创建一个指向另一个类中的静态列表的变量。

      好的,让我们从另一个类中的静态列表开始。别笑:

      public class AnotherClass {
      
        public static SubscribeList<String> List;
      
        static AnotherClass() {
          List = new SubscribeList<string>();
          List.OnListContentsChange += new EventHandler(List_ContentsChanged);
        }
      
        private static void List_ContentsChanged(object sender, EventArgs e) {
          Console.WriteLine("The contents of the list have changed! Call your Redraw Code.");
        }
      
      }
      

      OnListContentsChanged EventHandler 必须连接起来,以便您的代码知道在列表更改时如何做出反应。

      现在,要在指向此列表的公共类中创建变量,您可以执行以下操作:

      public class PublicClass {
      
        private SubscribeList<String> list;
      
        public PublicClass() {
          list = AnotherClass.List;
        }
      
        private void someButton_Click(object sender, EventArgs e) {
          list.Add("Someone or txtName.Text from your form"); // this will fire the AnotherClass.List_ContentsChanged EventHandler.
        }
      
      }
      

      请注意,我创建了一个虚构的按钮单击事件,它将一个项目添加到您的静态列表中。

      另外,请注意,如果您在 AnotherClass 中的 List 从未创建过,您将在此处抛出异常。

      如果这不是你想要的,那我就是不明白你的问题。

      【讨论】:

      • 您实现ObservableCollection&lt;T&gt; 中已有的内容有什么原因吗?
      • ObservableCollectionWPF,并且OP特别声明了WinForms。他可能无法访问 WPF 库/框架。此外,还有很多其他的 cmets 已经告诉他关于 ObservableCollection 的事情,而他没有接受这些。 ObservableCollection 不能总是放入一个已经在使用老式 List 而不进行编码修改的大项目中。
      • ObservableCollection&lt;T&gt;NOT WPF,它在 System.dll.
      • 这个答案是浪费时间。使用 ObservableCollection。任何人都会这样做
      • @j2pcode 如果ObservableCollection 不能总是被放入一个已经使用老式List&lt;T&gt; 而不进行编码修改的大项目中,您提供的解决方案也不能。 -1 来自我。
      猜你喜欢
      • 1970-01-01
      • 2012-09-11
      • 1970-01-01
      • 1970-01-01
      • 2011-12-16
      • 2014-05-12
      • 1970-01-01
      • 2023-03-22
      • 2023-02-05
      相关资源
      最近更新 更多