【问题标题】:Correct Event handling in C#C# 中的正确事件处理
【发布时间】:2014-11-28 10:27:01
【问题描述】:

这基本上是对上一个问题 (Triggering an event in c# from c++ and declaring LPCWSTR) 的跟进。我根据收到的答案和 cmets 修改了我的代码,并解决了最初的问题,即从 gpio api 将事件传递给 GpioSetupInterruptPin。我没有很多关于 api 的文档,但我想要实现的是:有一个带有白色标签的表单;按下开关后,标签变为黄色。 我现在遇到的问题是事件似乎在创建后立即触发(“执行”消息被传递到调试对话框并且标签变为黄色)但是当我切换开关时它没有做任何事情。我在最后一个问题中被告知要使用 WaitForSingleObject,但我不确定在哪里调用它,this article 只会让我更加困惑。

public partial class Form1 : Form
{
    // P/Invoke CreateEvent and WaitForSingleObject
    private void GPIO_Open() //get handle for gpio
    private void GPIO_Output() //output pin declaration

    private void button1_Click(object sender, EventArgs e)
    {
        Interrupt_Setup();
    }

    private void Interrupt_Setup()
    {
        hGPIO = GPIOapi.GpioOpenHandle(); //returns a handle to the gpio
        GIPO_ON = true;
        Debug.WriteLine("Driver open \n" + hGPIO);
        GPIO_Output(); //set output pins
        GPIO_Interrupt(Trigger); //configure interrupt
    }

    private void GPIO_Interrupt(string trigger)
    {
        bool ok;
        _Main();
        //INTERRUPT DECALRATION
        ok = GPIOapi.GpioSetupInterruptPin(hGPIO, port6, 4, GPIOapi.INT_TRIGGER_MODE.TRIGGER_MODE_EDGE,
            GPIOapi.INT_TRIGGER_POLARITY.TRIGGER_POL_HIGH_RISING, trigger, true);
        Thread waitThread=new Thread(WaitForTrigger);
        waitThread.Start();
        if (!ok)
            Debug.WriteLine("NO interrupt");
        else
            Debug.WriteLine("Interrupt set for:" + port6 + "04" + " at " + hGPIO);
    }

    public static string Trigger = "InputProcessUpdateHandler";
    public static IntPtr handle = CreateEvent(IntPtr.Zero, false, false, Trigger); //used P/Invoke 
    private static InputProcessor inputProcessor = null;

    public Color[] color =
    {
        Color.Orchid, Color.DarkOrchid, Color.GreenYellow, Color.CornflowerBlue, Color.SteelBlue,Color.Crimson
    };

    public int i = 0;

    public void WaitForTrigger()
    {
        while(true)
        {try
        {
            if (WaitForSingleObject(handle, 0xFFFFFFFF) == false)
            {
                BeginInvoke(((System.Action)(() =>label2.BackColor = color[i])));
                i++;
                if (i > 4)
                    i = 0;
            }
            Thread.Sleep(300);
        }
        catch (Exception e)
        { Debug.WriteLine("exception: " + e); }}
        }
    }

    private void _Main()
    {
        inputProcessor = new InputProcessor();
        ShowToggle showToggle = new ShowToggle(inputProcessor);
        inputProcessor.Process(label1);
    }

    public class ShowToggle
    {
        private InputProcessor _inputProcessor = null;

        public ShowToggle(InputProcessor inputProcessor)
        {
            _inputProcessor = inputProcessor;
            _inputProcessor.updateHandledBy += InputProcessUpdateHandler;
        }

        private void InputProcessUpdateHandler(Label label)
        {
            label.BackColor = Color.Yellow;
            Debug.Write("execute");
        }
   }

   public class InputProcessor
   {
       public delegate void InputProcessUpdateHandler(Label label);
       public event InputProcessUpdateHandler updateHandledBy = null;

       public void Process(Label label)
      {
          if (updateHandledBy != null)
            updateHandledBy(label);
      }
   }

如果有人能帮我解决这个问题,我将不胜感激。

*** 我得到了它的工作,但它看起来一团糟。谁能帮我解决一下?

【问题讨论】:

  • 我不清楚为什么你有额外的两个类,它们似乎只是封装了事件和处理程序。该事件可以说应该驻留在封装 GPIO 功能的同一类中(不清楚您是否真的拥有其中之一),并且处理程序本身可以只是在 Form1 类中。也就是说,这里最大的问题似乎是您缺少任何从 GPIO 实现接收信号的机制。您似乎得到的最接近的是创建 handle 实例,但这似乎根本没有被使用,更不用说传递给 GPIO。
  • 抱歉,我的回复延迟了很长时间(家庭紧急情况和大量工作)。代码相当混乱,因为我开始为委托和事件做一些示例,而上面的代码只是我尝试组合它们

标签: c# winapi event-handling windows-ce


【解决方案1】:

你的代码让我很困惑。我想你想要的是这样的。请记住,我将其输入到 SO 文本编辑器中,所以不要期望它能够编译并正常工作 - 它是一个指南。认为它比伪代码高出一步。

public class DeviceInterrupt
{
    IntPtr m_gpio;
    string m_eventName;

    public event EventHandler OnInterrupt;

    public DeviceInterrupt(int port)
    {
        // get a driver handle
        m_gpio = GPIO_Open();

        // generate some unique event name
        m_eventName = "GPIO_evt_" + port;

        // wire up the interrupt
        GpioSetupInterruptPin(m_gpio, port, m_eventName, ...);

        // start a listener
        new Thread(EventListenerProc)
        {
            IsBackground = true,
            Name = "gpio listener"
        }
        .Start();
    }

    public void Dispose()
    {
        // TODO: release the handle
    }

    private void EventListenerProc()
    {
        // create the event with the name we sent to the driver
        var wh = new WaitHandle(false, m_eventName);

        while (true)
        {
            // wait for it to get set by the driver
            if (wh.WaitOne(1000))
            {
                // we have an interrupt
                OnInterrupt.Fire(this, EventArgs.Empty);
            }
        }
    }
}

用法会是这样的:

var intr = new DeviceInterrupt(4);
intr.OnInterrupt += MyHandler;
....
void MyHandler(object sender, EventArgs a)
{
    Debug.WriteLine("Interrupt occurred!");
}

注意

Compact Framework 不支持实际的命名系统事件,因此我在上面的代码中使用的命名WaitHandle 不是 CF 提供的WaitHandle。相反,我使用的是来自Smart Device Framework 的那个。您也可以自己 P/Invoke 到 CreateEventWaitForSingleObject

【讨论】:

  • 您好,感谢您的指导,因为它使事情变得有点清晰。你介意给我一些关于 WaitHandle() 的额外帮助吗?我尝试过使用它,但出现错误“无法在此处访问受保护的构造函数”。我尝试使用 EventWaitHandle() 但我无法让它工作
  • 您不能使用 CF 提供的 WaitHandle。 CF 团队的无限愚蠢导致他们不支持实际的命名事件,因此您要么必须使用 P/Invoke 自己调用 API,要么使用(免费、开源)SDF 版本 - 位于 opennetcf.codeplex.com
猜你喜欢
  • 2012-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-31
  • 1970-01-01
  • 1970-01-01
  • 2015-05-22
相关资源
最近更新 更多