从多个类访问控件. (再次) [英] Accessing control from multiple classes. (again)

查看:59
本文介绍了从多个类访问控件. (再次)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法正常工作.我有一个Form和数十个类,我想从这些类中访问Form的Listview. ListViewFunc是帮助程序类,而SomeClass是许多其他类之一.我也尝试过代表和活动,但是没有运气.所以基本上我只想从任何位置编写ListViewFunc.Add().这是2个示例.

1.使用公共财产

I just can''t get this working. I have one Form and dozen of classes and I want to access form''s listview from those classes. ListViewFunc is helper class and SomeClass is one of many other classes. I have tried also delegates and events, but with no luck. So basically I want just to write ListViewFunc.Add() from any location. Here''s 2 samples.

1. Use public property

//************************
// ****** FORM1.CS ******
//************************
namespace WindowsFormsApplication
{
    public partial class Form1 : Form
    {
        public string SetText
        {
            set { listView1.Items.Add(value); }
        }
        public Form1()
        {
            InitializeComponent();
        }
    }
}

//*******************************
// ****** LISTVIEWFUNC.CS ******
//*******************************
namespace WindowsFormsApplication
{
    class ListViewFunc
    {
        private Form1 _form;
        public ListViewFunc(Form1 form)
        {
            _form = form;
        }
        public void Add(string txt)
        {
            _form.SetText = txt;
        }
    }
}

//*****************************
// ****** SOMECLASS.CS *******
//*****************************
namespace WindowsFormsApplication
{
    class SomeClass
    {
        // How should I call ListViewFunctions.Add() from here or some other class?

         // Won't work because Add() isn't static
        ListViewFunctions.Add("wrong");
        
        // Won't work without constuctors parameters and don't want to send Form1 as param to every class
        ListViewFunctions myFunc = new ListViewFunctions();
        myFunc.Add("wrong");
    }
}


2.使用界面


2. Using interface

//************************
// ****** FORM1.CS ******
//************************
namespace WindowsFormsApplication
{
    public partial class Form1 : Form, IlstView
    {
        public Form1()
        {
            InitializeComponent();
        }
        public void AddTxt(string txt)
        {
            listView1.Items.Add(txt);
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            ListViewFunc.Add("Just calling from here to test");
        // No changes in listview
        }
    }
}
public interface IlstView
{
    void AddTxt(string txt);
}

//*******************************
// ****** LISTVIEWFUNC.CS ******
//*******************************
namespace WindowsFormsApplication
{
    class ListViewFunc
    {
        private Form1 _form;
        public ListViewFunc(Form1 form)
        {
            _form = form;
        }
        public static void Add(string txt)
        {
            // This is wrong? How to use _form here?
            IlstView ilstview = (IlstView)new Form1(); 
            ilstview.AddTxt(txt);
            // Now if I call Add("something"); nothing happens in listView
            
        }
    }
}
//*****************************
// ****** SOMECLASS.CS *******
//*****************************
namespace WindowsFormsApplication
{
    class SomeClass
    {
        public void TestMethod()
        {
            ListViewFunc.Add("ListView won't be changed");
        }
    }
}

推荐答案

没有图片很难解释,但是基本上您需要访问属于表单实例的ListView实例-这就是为什么它总是抱怨静电之类的原因.
因为您试图通过类访问它,所以引起了很多问题:您应该只从创建它们的类中访问UI元素.别的就是糟糕的设计,因为它将两个项目的设计锁定在一起-这是一个坏主意.

理想情况下,您需要做的是在每个子类中创建一个事件,说我有数据!"并允许其他类在创建类实例时愿意的话订阅该类:
表格1:
This isn''t too easy to explain without pictures, but basically you need access to the ListView instance which is part of your form instance - that''s why it keeps complaining about static and so forth.

Because you are trying to access it via classes you are causing a lot of problems: you should only access UI elements from the class in which they are created. Anything else is bad design, because it locks the design of the two items together - a bad idea.

What you need to do, ideally, is create an event in each subclass which says "I have Data!" and allow your other classes to subscribe to that if they so wish when they create the class instance:
Form1:
MyClass1 mc1 = new MyClass1();
mc1.HasNewData += new EventHandler(mc1_HasNewData);
MyClass2 mc2 = new MyClass2();
mc2.HasNewData += new EventHandler(mc2_HasNewData);

如果MyClass1或MyClass2创建类,则它们将为它们处理事件,并通过MyClass1或MyClass2我有数据!"来传递数据.事件.

If MyClass1 or MyClass2 create classes, they handle the event for them, and hand the data on up through the MyClass1 or MyClass2 "I have Data!" event.


作为Griff提出的基于事件的模型的替代方案,您还可以采用基于模型/视图的方法,并获取主要表单正在使用的数据模型的实例.也可用于其他班级. MVVM通常用于WPF/Silverlight,但这些原理同样适用于WinForms.在这种情况下,您的ListView将被绑定到列表*,因此请公开BindingList< string>.或模型中类似的东西,并从其他类向其中添加项目.例如:

As an alternative to the event based model proposed by Griff, you can also take a model/view based approach, and have the instance of the data model that the main form is using also be available to the other classes. MVVM is normally used for WPF/Silverlight but the principles can equally apply to WinForms. In this case your ListView will be bound to a list*, so expose a BindingList<string> or something similar in the model, and add items to it from other classes. E.g.:

class ListViewDataModel {
 BindingList<string> Messages {get; private set; }

 ListViewViewModel() { Messages = new BindingList<string> }
}

partial class Form1 : Form {
 ListViewDataModel model;
 
 Form1(ListViewDataModel model){ 
  InitializeComponent();

  this.model = model;
  BindList(listView1, model.Messages);
 }
 ...
} 

class SomeOtherClass {
 ListViewDataModel model;
 
 SomeOtherClass(ListViewDataModel model){ 
  this.model = model;
 }

 public void TestMethod()
 {
   model.Messages.Add("Test message");
 }
}



现在,您需要在某个地方创建并存储该模型的实例,并将其传递给表单和其他类的构造函数.但是,表单和其他类是独立的–他们不在乎谁发送或接收消息.如果这是您的主要形式,则可以在启动文件(通常是Program.cs)中创建数据模型的静态全局实例,否则可以在您的主要业务事件创建者(通常是主要形式)中创建该实例的实例.其他课程.在不了解更多问题的情况下,这就是我可以在何处创建模型的所有建议.

您是喜欢通过Griff建议的事件还是通过这样的视图模型关系来分离组件,很大程度上取决于您的口味.

*:WinForms ListView似乎不直接支持数据绑定,因此您将必须进行基本的只读绑定(如果您想做的事情不仅仅是添加新的内容,可以进行扩展.行):



Now you need to create and store an instance of that model somewhere and pass it to the constructor of the form and the other classes. However, the form and the other classes are independent – they don''t care who sent or received their messages. If this is your main form, then you could create a static global instance of the data model in the startup file (usually Program.cs), otherwise within whatever is your main business event creator (usually the main form) which creates the instances of the other classes. Without knowing more about the problem, that''s all the advice on where to create the model I can give.

Whether you prefer to decouple components via events as Griff suggests or via a view-model relationship like this is largely a matter of taste.

*: The WinForms ListView doesn''t appear to support data binding directly, so you will have to do a rudimentary readonly binding (which can be expanded if you want to do more than just adding new rows):

void BindList(ListView lv, IBindingList model){
 model.ListChanged += (s,e) => {
  switch(e.ListChangedType){
   case ListChangedType.ItemAdded:
    lv.Items.Add(model[e.NewIndex]);
   default: throw new NotImplementedException();
 };
}




这篇关于从多个类访问控件. (再次)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆