我正在使用WPF使用C#构建应用程序,应用程序需要不断订阅由第三方服务器生成的事件,并根据收到的事件更新UI控件,最初我需要连接到服务器在事件发出之前,连接是一个昂贵的操作,所以我把它放在一个单独的线程上,我使用WPF Dispatcher BeginInVoke和一个委托方法来订阅事件,现在问题是这将在以后的某个时候工作正常我运行应用程序,我的意思是UI控件将在停止接收通知之前通知一段时间,我尝试设置停止点并进入代码,委托调用的方法不被调度程序和第三方调用派对服务器是连续发布事件,但我的调度员不会再次发现它,我已经尝试了所有可能的方法,但我找不到任何解决方案,任何有帮助和解决方案的人都将不胜感激
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Text.RegularExpressions;
using System.Windows.Threading;
using System.Media;
using ClientPhone.Utility;
using System.Threading.Tasks;
using ClientPhone.Core.DAL;
using ClientPhone.Core.Model;
namespace ClientPhone.View
{
/// <summary>
/// Interaction logic for TestView.xaml
/// </summary>
public partial class TestView : Window
{
private FreeSwitchEventHandler _freeSwitchEventHandler;
private delegate void EventDelegate(switch_event evt);
public static NotificationInfo _notificationInfo;
private EventDelegate del;
public TestView()
{
InitializeComponent();
del = new EventDelegate(actual_event_handler);
ConnectToServer();
}
private void ConnectToServer()
{
string err = string.Empty ;
const uint flags = (uint)(switch_core_flag_enum_t.SCF_USE_SQL | switch_core_flag_enum_t.SCF_USE_AUTO_NAT);
freeswitch.switch_core_set_globals();/*Next 3 lines only needed if you want to bind to the initial event or xml config search loops */
freeswitch.switch_core_init(flags, switch_bool_t.SWITCH_FALSE, ref err);
IDisposable search_bind = FreeSWITCH.SwitchXmlSearchBinding.Bind(xml_search, switch_xml_section_enum_t.SWITCH_XML_SECTION_CONFIG);
event_bind = FreeSWITCH.EventBinding.Bind("SampleClient", switch_event_types_t.SWITCH_EVENT_ALL, null, event_handler, true);
}
private void event_handler(FreeSWITCH.EventBinding.EventBindingArgs args)
{
Dispatcher.BeginInvoke(del, DispatcherPriority.Send,new object[] { args.EventObj });
}
private void actual_event_handler(switch_event evt)
{
_eventInfo = _eventHandler.HandleEvents(evt);
if (_eventInfo != null && _eventInfo.Callee == _userId)
{
if ((!_callState.IsCallIncoming && _eventInfo.State!="hangup")&& _eventInfo.Caller!=null)
{
SetIsAnsweredParameters()
}
}
if (_eventInfo != null && (_eventInfo.ChannelState == "CS_DESTROY" || _eventInfo.ChannelState == "CS_HANGUP"))
{
ResetUIState();
}
}
private void SetIsAnsweredParameters()
{
if (!_isTimercounting)
{
_timerMinutes = 0;
_timerSeconds = 0;
_callState.IsCallActive = true;
_isTimercounting = true;
_soundManager.StopPlayer();
_timer.Interval = TimeSpan.FromSeconds(1);
_timer.Start();
grdNotification.Visibility = Visibility.Visible;
}
}
private void UpdateHistory(string call)
{
lstHistory.Items.Add(call);
}
} }
答案 0 :(得分:1)
听众可能会抛出异常。你不会知道它,因为我怀疑你没有调用EndInvoke将异常重新加入主线程。
将您的代码更改为:
Action action = () => ... ;
action.BeginInvoke(action.EndInvoke, null);
当服务现在失败时,你将在主线程上获得异常,并通过查看堆栈跟踪来解决导致它的原因。
修改强>
这不应该是必要的,因为您实际上正在使用在UI线程上运行的Dispatcher.BeginInvoke
。
我建议添加一些日志记录,并尝试使用first chance exceptions enabled在Visual Studio中进行调试。
var op = Dispatcher.BeginInvoke(del, DispatcherPriority.Send,
new object[] { args.EventObj });
op.Completed += (s,e) => logger.Debug("Completed");
op.Aborted += (s,e) => logger.Debug("Aborted");
答案 1 :(得分:0)
一种可能性是FreeSwitch
模块实际上将处理程序传递给非托管代码。在这种情况下,GC不会知道委托实际上是可以访问的并且会收集它。您可以通过创建成员字段来存储event_handler
委托:
_newEventDelegateMember = new ProperDelegateType(event_handler);
event_bind = FreeSWITCH.EventBinding.Bind("SampleClient",
switch_event_types_t.SWITCH_EVENT_ALL, null,
**_newEventDelegateMember**, true);