VideoControl自定义方法调用异常:实例调用无法正常播放视频
问题
我正在尝试为VideoControl.cs添加一个函数方法,以便从Form1.cs的按钮点击事件中调用,所用代码基于一个VLC播放器项目。
目前启动视频的方式是在窗体的videoControl1控件内右键,从右键菜单选择Load选项,该操作会触发VideoControl.cs中的loadFileToolStripMenuItem_Click函数,可正常播放视频。
我编写了一个public静态方法testingVid,期望直接传入视频路径无需文件选择弹窗,代码如下:
public static void testingVid(string theVideo) { m_fileName = theVideo; m_lastPlayedIsFile = true; Play(out string outMessage); if (pCallback != null) { foreach (IVideoControl p in pCallback) { p.NotifyPlay(m_fileName, true); } } }
从Form1.cs中以VideoControl.testingVid(@"C:\Users\Admin\Videos\a_test_video.mp4")调用时,出现CS0120错误:非静态字段、方法或属性需要对象引用。
改为创建类实例调用:
VideoControl VC = new VideoControl(); VC.testingVid(@"C:\Users\Admin\Videos\a_test_video.mp4");
无报错但无法像右键菜单那样正常播放视频,调试发现两种方式的最终数据一致,请问问题出在哪里?
问题原因及解决方法
1. 静态方法调用报错的原因
testingVid被定义为静态方法,但方法内直接访问了m_fileName、m_lastPlayedIsFile、pCallback这些非静态成员——这些成员属于VideoControl的实例对象,而非类本身,静态方法无法直接访问实例成员,因此触发CS0120错误。
2. 新建实例无法播放的原因
你新建的VideoControl实例VC是一个完全独立的控件对象,它没有被添加到窗体的控件树中,也和界面上已经显示的videoControl1控件没有任何关联。右键菜单触发的是已在窗体上初始化完成、与界面绑定的videoControl1实例的方法,两者不是同一个对象,所以新实例调用方法不会在界面上呈现播放效果。
正确实现方式
方式一:直接复用窗体上已有的videoControl1实例(推荐)
把testingVid改成非静态方法,去掉static关键字:
public void testingVid(string theVideo) { m_fileName = theVideo; m_lastPlayedIsFile = true; Play(out string outMessage); if (pCallback != null) { foreach (IVideoControl p in pCallback) { p.NotifyPlay(m_fileName, true); } } }
然后在Form1.cs的按钮点击事件中,直接调用界面上已有的videoControl1控件的方法:
videoControl1.testingVid(@"C:\Users\Admin\Videos\a_test_video.mp4");
这种方式和右键菜单的逻辑完全一致,操作的是同一个控件实例,就能正常播放视频。
方式二:静态方法调用(仅单实例场景适用)
如果一定要用静态方法,可以在VideoControl类中维护一个静态实例引用,用于指向窗体上的videoControl1:
// 在VideoControl类中添加静态实例引用 public static VideoControl CurrentInstance { get; private set; } // 在VideoControl的构造函数中赋值 public VideoControl() { InitializeComponent(); CurrentInstance = this; } // 修改静态方法,通过静态引用访问实例成员 public static void testingVid(string theVideo) { if (CurrentInstance == null) return; CurrentInstance.m_fileName = theVideo; CurrentInstance.m_lastPlayedIsFile = true; CurrentInstance.Play(out string outMessage); if (CurrentInstance.pCallback != null) { foreach (IVideoControl p in CurrentInstance.pCallback) { p.NotifyPlay(CurrentInstance.m_fileName, true); } } }
之后在Form1.cs中直接调用静态方法即可:
VideoControl.testingVid(@"C:\Users\Admin\Videos\a_test_video.mp4");
注意:这种方式仅适用于窗体中只有一个VideoControl实例的场景,多实例场景会出现逻辑混乱。
内容的提问来源于stack exchange,提问作者StealthRT

