Everyone!!!
I am studying BluetoothLE. Can you give me some advice if you can’t help me?
Studying the example source of BluetoothLE in Windows 10 Universal Windows:Character_ValueChanged () does not respond to the Characteristic function. In the example source, the value change is called a function recall, but it does not respond to WinForm.
Please….
private GattCharacteristic registeredCharacteristic;
Hi.
I am studying BluetoothLE. And then I looked at the data and then I saw the blog. Can you give me some advice if you can’t help me?
Studying the example source of BluetoothLE in Windows 10 Universal Windows:Character_ValueChanged () does not respond to the Characteristic function. In the example source, the value change is called a function recall, but it does not respond to WinForm.
Please….
private GattCharacteristic registeredCharacteristic;
.
.
private async void BTN_Change_SubscribeToggle_Click(object sender, EventArgs e)
{
if (!subscribedForNotifications)
{
// initialize status
GattCommunicationStatus status = GattCommunicationStatus.Unreachable;
var cccdValue = GattClientCharacteristicConfigurationDescriptorValue.None;
if (selectedCharacteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Indicate))
{
cccdValue = GattClientCharacteristicConfigurationDescriptorValue.Indicate;
}
else if (selectedCharacteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify))
{
cccdValue = GattClientCharacteristicConfigurationDescriptorValue.Notify;
}
Debug.WriteLine("[ cccdValue = {0} ]", cccdValue);
try
{
// BT_Code: Must write the CCCD in order for server to send indications.
// We receive them in the ValueChanged event handler.
status = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue);
Debug.WriteLine("[ status = {0} ]", status);
if (status == GattCommunicationStatus.Success)
{
AddValueChangedHandler();
Notify_User("Successfully subscribed for value changes", NotifyType.StatusMessage);
}
else
{
Notify_User("Error registering for value changes : " + status.ToString(), NotifyType.ErrorMessage);
}
}
catch (UnauthorizedAccessException ex)
{
// This usually happens when a device reports that it support indicate, but it actually doesn't.
Notify_User(ex.Message, NotifyType.ErrorMessage);
}
} // if(!subscribedForNotifications)
else
{
try
{
// BT_Code: Must write the CCCD in order for server to send notifications.
// We receive them in the ValueChanged event handler.
// Note that this sample configures either Indicate or Notify, but not both.
var result = await
selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
GattClientCharacteristicConfigurationDescriptorValue.None);
Debug.WriteLine("[ result = {0} ]", result);
if (result == GattCommunicationStatus.Success)
{
subscribedForNotifications = false;
RemoveValueChangedHandler();
Notify_User("Successfully un-registered for notifications", NotifyType.StatusMessage);
}
else
{
Notify_User("Error un-registered for notifications : " + result, NotifyType.ErrorMessage);
}
}
catch (UnauthorizedAccessException ex)
{
Notify_User(ex.Message, NotifyType.ErrorMessage);
}
} // else
}
private void AddValueChangedHandler()
{
Debug.WriteLine("[ AddValueChangedHandler() ]");
Debug.WriteLine("[ subscribedForNotifications = {0} ]", subscribedForNotifications);
BTN_Change_SubscribeToggle.Text = "Unsubscribe from value changes";
if (!subscribedForNotifications)
{
registeredCharacteristic = selectedCharacteristic;
registeredCharacteristic.ValueChanged += Characteristic_ValueChanged;
subscribedForNotifications = true;
CTR_Update_Visible(LB_Value, true);
CTR_Update_Msg(LB_Value, "test");
}
}
private async void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
// BT_Code: An Indicate or Notify reported that the value has changed.
// Display the new value with a timestamp.
//var reader = DataReader.FromBuffer(args.CharacteristicValue);
Debug.WriteLine("[ Characteristic_ValueChanged ]");
var newValue = FormatValueByPresentation(args.CharacteristicValue, presentationFormat);
var message = string.Format("Value at {0} : \r\n\t {1}", DateTime.Now.ToString("HH:mm:ss.FFF"), newValue);
}
All I could understand is this:
the value change is called a function recall, but it does not respond to WinForm.
To fix it try removing the Async from the button click:
private async void BTN_Change_SubscribeToggle_Click(object sender, EventArgs e)
{
Related
I want to get the text input of the CoreTextServicesManager, but the TextUpdating event is not even triggered. In my UWP project, it is working fine.
This is how I create the Service:
CoreTextServicesManager manager = CoreTextServicesManager.GetForCurrentView();
CoreTextEditContext EditContext = manager.CreateEditContext();
EditContext.InputPaneDisplayPolicy = CoreTextInputPaneDisplayPolicy.Manual;
EditContext.InputScope = CoreTextInputScope.Text;
EditContext.TextRequested += delegate { };
EditContext.SelectionRequested += delegate { };
EditContext.TextUpdating += EditContext_TextUpdating;
EditContext.FocusRemoved += EditContext_FocusRemoved;
EditContext.NotifyFocusEnter();
Here are my events:
private void EditContext_TextUpdating(CoreTextEditContext sender,
CoreTextTextUpdatingEventArgs args)
{
Debug.WriteLine(args.Text);
}
private void EditContext_FocusRemoved(CoreTextEditContext sender, object args)
{
Debug.WriteLine("Lost focus");
}
Why does the TextUpdating event not trigger? what am I doing wrong?
I'm not sure if you've already seen this (late reply after I found this question by Google), but support for some UWP APIs was unfortunately dropped. This article suggests some replacements and workarounds for some of them.
https://learn.microsoft.com/en-gb/windows/apps/desktop/modernize/desktop-to-uwp-supported-api
We have it working in our UWP app. Make sure you're on the main thread
imeInputPane = CoreInputView.GetForCurrentView();
imeInputPane.PrimaryViewShowing += ImeInputPane_PrimaryViewShowing;
imeInputPane.PrimaryViewHiding += ImeInputPane_PrimaryViewHiding;
imeTextContext = CoreTextServicesManager.GetForCurrentView().CreateEditContext();
// Manually control when soft keyboard shows. When hard keyboard is attached, the
// soft keyboard will never show.
imeTextContext.InputPaneDisplayPolicy = CoreTextInputPaneDisplayPolicy.Manual;
// the default keyboard is general purpose soft keyboard, has no affect with hard keyboard
imeTextContext.InputScope = CoreTextInputScope.Text;
imeTextContext.TextRequested += IMETextContext_TextRequested;
imeTextContext.SelectionRequested += IMETextContext_SelectionRequested;
imeTextContext.FocusRemoved += IMETextContext_FocusRemoved;
imeTextContext.TextUpdating += IMETextContext_TextUpdating;
imeTextContext.SelectionUpdating += IMETextContext_SelectionUpdating;
imeTextContext.FormatUpdating += IMETextContext_FormatUpdating;
imeTextContext.LayoutRequested += IMETextContext_LayoutRequested;
imeTextContext.CompositionStarted += IMETextContext_CompositionStarted;
imeTextContext.CompositionCompleted += IMETextContext_CompositionCompleted;
...
private void IMETextContext_TextUpdating(CoreTextEditContext sender, CoreTextTextUpdatingEventArgs args)
{
string origText = imeText;
CoreTextRange range = args.Range;
CoreTextRange newSelection = args.NewSelection;
//Modify the internal text store for the IME
imeText = imeText.Substring(0, range.StartCaretPosition)
+ args.Text
+ imeText.Substring(Math.Min(imeText.Length,
range.EndCaretPosition));
newSelection.EndCaretPosition = newSelection.StartCaretPosition;
Debug.WriteLine(string.Format("IME SendReplaceText Orig Text '{0}' New Text '{1}' StartCaret '{2}' EndCaret '{3}'", origText, imeText, imeSelection.StartCaretPosition, imeSelection.EndCaretPosition - imeSelection.StartCaretPosition));
// Do something with the text
SendReplaceText(args.Text // new text
, range.StartCaretPosition // start position
, range.EndCaretPosition - range.StartCaretPosition // length of former text that is being replaced
, args.Text.Length); // length of the modified text
imeSelection = newSelection;
args.Result = CoreTextTextUpdatingResult.Succeeded;
}
private void IMEBypassControl_OnShowKeyboard(object sender, IMEBypassShowKeyboardEventArgs e)
{
try
{
if (e.Visible)
{
Task.Run(async () =>
{
if (MiscUtils.AreWeOnMainUIThread)
{
try
{
LOG.LogV(string.Format("IME Show Keyboard '{0}' Start '{1}' Total Size '{2}", e.Text, e.CursorPosition, e.FetchSize));
//Debug.WriteLine(string.Format("IME Show Keyboard '{0}' Start '{1}' Total Size '{2}", e.Text, e.CursorPosition, e.FetchSize));
imeTextContext.InputScope = CoreTextInputScope.Text;
imeText = e.Text;
imeSelection.StartCaretPosition = e.CursorPosition;
imeSelection.EndCaretPosition = e.CursorPosition;
imeTextContext.NotifyTextChanged(imeSelection, e.Text.Length, imeSelection);
SetFocus();
}
catch (Exception ex)
{
LOG.LogE(ex);
}
}
else
{
await MiscUtils.CallOnMainViewUiThreadAsync(() =>
{
try
{
LOG.LogV(string.Format("IME Show Keyboard '{0}' Start '{1}' Total Size '{2}", e.Text, e.CursorPosition, e.FetchSize));
//Debug.WriteLine(string.Format("IME Show Keyboard '{0}' Start '{1}' Total Size '{2}", e.Text, e.CursorPosition, e.FetchSize));
imeTextContext.InputScope = CoreTextInputScope.Text;
imeText = e.Text;
imeSelection.StartCaretPosition = e.CursorPosition;
imeSelection.EndCaretPosition = e.CursorPosition;
imeTextContext.NotifyTextChanged(imeSelection, e.Text.Length, imeSelection);
SetFocus();
}
catch (Exception ex)
{
LOG.LogE(ex);
}
});
}
}).GetAwaiter().GetResult();
}
else
{
RemoveFocus();
}
}
catch (Exception ex)
{
LOG.LogE(ex);
}
}
else
{
RemoveFocus();
}
}
private void SetFocus()
{
imeTextContext.NotifyFocusEnter();
}
public void RemoveFocus()
{
if (MiscUtils.AreWeOnMainUIThread)
{
imeTextContext.NotifyFocusLeave();
imeInputPane.TryHide();
}
else
{
Task.Run(async () =>
{
await MiscUtils.CallOnMainViewUiThreadAsync(() =>
{
imeTextContext.NotifyFocusLeave();
imeInputPane.TryHide();
});
}).GetAwaiter().GetResult();
}
}
I have an async function which still freezes / lags the UI thread for me when I execute it. This is my function calling it.
private void TcpListenerLogic(object sender, string e)
{
Application.Current.Dispatcher.BeginInvoke((Action)async delegate {
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
// Get properties for new anchor
string testInformation = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + results.test_id);
}
}
catch (Exception exception)
{
// Writing some Trace.WriteLine()'s
}
});
}
And this is the async function that freezes my UI Thread
public static async Task<string> getJsonFromURL(string url)
{
try
{
string returnString = null;
using (System.Net.WebClient client = new System.Net.WebClient())
{
returnString = await client.DownloadStringTaskAsync(url);
}
return returnString;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return null;
}
}
I already tried to make everything in TcpListenerLogic run in a new Thread:
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
}).Start();
Which resulted in the whole UI completely freezing. And I tried to make TcpListenerLogic async and await the dispatcher, which also made everything freeze permanently. I also tried to make TcpListenerLogic async and leave the dispatcher. The dispatcher is only there because I normally have some UI code in there, which I left out for my tests.
I have ventured far through the internet, but no BackgroundWorker, ThreadPool or other methods helped me in my endeavour.
If anyone has help for this particular problem, or a resource that would improve my understanding of async functions in C#, I would much appreciate it.
Edit
As requested a deeper insight in how this event handler is called.
I have System.Net.Websocket, which is connected to the Backend API I am working with and triggers an event, everytime he receives new Data. To guarantee the socket listens as longs as it is open, there is a while loop which checks for the client state:
public event EventHandler<string> TcpReceived;
public async void StartListener(string ip, int port, string path)
{
try
{
using (client = new ClientWebSocket())
{
try
{ // Connect to backend
Uri serverUri = new Uri("ws://" + ip + ":" + port.ToString() + path );
await client.ConnectAsync(serverUri, CancellationToken.None);
}
catch (Exception ex)
{
BackendSettings.IsConnected = false;
Debug.WriteLine("Error connecting TCP Socket: " + ex.ToString());
}
state = client.State;
// Grab packages send in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
try
{
// **Just formatting the received data until here and writing it into the "message" variable**//
TcpReceived(this, message);
// Close connection on command
if (result.MessageType == WebSocketMessageType.Close)
{
Debug.WriteLine("Closing TCP Socket.");
shouldstayclosed = true;
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
break;
}
state = client.State;
}
catch
{
BackendSettings.IsConnected = false;
state = client.State;
}
}
state = client.State;
}
}
catch (Exception ex)
{
// Some error messages and settings handling
}
}
The Event has a handler attached:
TcpReceived += TcpListener_TcpReceived;
And this is the Handler, which calls the previously seen "TcpListenereLogic".
private void TcpListener_TcpReceived(object sender, string e)
{
TcpListenerLogic(sender, e);
//App.Current.Dispatcher.BeginInvoke(new Action(() => {
// TcpListenerLogic(sender, e);
//}));
//new Thread(() =>
//{
// Thread.CurrentThread.IsBackground = true;
// TcpListenerLogic(sender, e);
//}).Start();
}
I previously had the "TcpListenereLogic" as the handler, but I wanted to try different methods to call it. I also left in the commented out part, to show how the call of "TcpListenereLogic" looked already. All my attempts were with all mentioned setups and sadly lead to nothing.
Thank you very much #TheodorZoulias for helping me to find the solution to my problem.
It turns out it wasn't the async function itself, but rather how often it gets called. It got called roughly ~120 times every second.
My solution starts by calling the Listener method over a new Thread:
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
MainWindow.tcpListener.StartListener(ip, portNumber, "/api/");
}).Start();
To limit the amount of calls that happen every second I added a dispatcher timer, that resets a bool after it has been used for a call, by my Event.
readonly System.Windows.Threading.DispatcherTimer packageIntervallTimer =
new System.Windows.Threading.DispatcherTimer();
bool readyForNewPackage = true;
private void ReadyForPackage(object sender, EventArgs e)
{
readyForNewPackage = true;
}
public async void StartListener(string ip, int port, string path)
{
packageIntervallTimer.Interval = TimeSpan.FromMilliseconds(50);
packageIntervallTimer.Tick += (s, e) => { Task.Run(() => ReadyForPackage(s, e)); };
packageIntervallTimer.Start();
Then I wrapped everything inside the while loop into an if condition based on the bool, the most important part was to have my "event EventHandler TcpReceived" in there:
// Grab packages sent in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
if (readyForNewPackage == true)
{
readyForNewPackage = false;
try
{
....
TcpReceived(this, message);
....
}
catch
{
...
}
}
}
I added my TcpListenerLogic to the Eventhandler:
TcpReceived += TcpListenerLogic;
And my TcpListenerLogic now looked like this (names have been changed):
private async void TcpListenerLogic(object sender, string e)
{
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
string testID = "";
if (results.test_id is JValue jValueTestId)
{
testID = jValueTestId.Value.ToString();
}
else if (results.test_id is string)
{
testID = results.test_id;
}
// Get properties for new object
string information = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + testID );
if (information != null)
{
await App.Current.Dispatcher.BeginInvoke(new Action(() =>
{
// Create object out of the json string
TestStatus testStatus = new TestStatus();
testStatus.Deserialize(information);
if (CommunicationCommands.isNameAlreadyInCollection(testStatus.name) == false)
{
// Add new object to the list
CommunicationCommands.allFoundTests.Add(testStatus);
}
}));
{
}
catch (Exception exception)
{
....
}
}
Adding a new Thread to execute any step results in problems, so keep in mind that all this uses the thread created at the beginning for "StartListener"
I have a function called getMessages that can be called by a Button click (using the RelayCommand trigger) or that is called in a timer every 15s.
The desired behavior is:
webservice > deserialize answer > system notification > updatelistview > insert localDB
But when the function is called by the timer the updatelistview is not done. Why does this happen if the function is the same and works perfectly in the button command?
CODE:
// Get messages for the logged in user
public async void getMessages()
{
try
{
List<FriendGetMessage> msg = new List<FriendGetMessage>();
var response = await CommunicationWebServices.GetCHAT("users/" + au.idUser + "/get", au.token);
if (response.StatusCode == HttpStatusCode.OK) // If there are messages for me.
{
var aux = await response.Content.ReadAsStringAsync();
IEnumerable<FriendGetMessage> result = JsonConvert.DeserializeObject<IEnumerable<FriendGetMessage>>(aux);
if (result != null)
{
foreach (var m in result)
{
msg.Add(m);
}
//MsgList=msg;
foreach (var f in Friends)
{
if (f.msg == null || f.msg.Count() == 0)
{
f.msg = new ObservableCollection<Messages>();
}
foreach (var mess in msg)
{
if (mess.idUser == f.idUser)
{
Messages mm = new Messages();
mm.received = mess.message;
mm.timestamp = "Received " + mess.serverTimestamp;
mm.align = "Right";
// Add to the friend list.
f.msg.Add(mm);
// Add to Local DB
InsertMessage(null, au.idUser.ToString(), f.idUser, mess.message, mess.serverTimestamp);
var notification = new System.Windows.Forms.NotifyIcon()
{
Visible = true,
Icon = System.Drawing.SystemIcons.Information,
BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info,
BalloonTipTitle = "New Message from " + f.name,
BalloonTipText = "Message: " + mess.message,
};
// Display for 5 seconds.
notification.ShowBalloonTip(5);
// The notification should be disposed when you don't need it anymore,
// but doing so will immediately close the balloon if it's visible.
notification.Dispose();
}
}
}
counterChat = 1; // resets the counter
}
}
else {
counterChat = counterChat * 2;
}
//var sql = "select * from chat";
//var respo = GetFromDatabase(sql);
OnPropertyChanged("Friends");
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
Debug.WriteLine("{0} Exception caught.", e);
}
}
CODE TIMER:
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
ADDED - I've also tried this and didn't worked (it seems that is some kind of concurrency problem to the ObservableCollection called Friends (is a friendslist) each friend has an ObservableCollection of messages (is a chat))
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
Application.Current.Dispatcher.Invoke((Action)async delegate { await getMessages(); });
incChat = 0;
}
}
Best regards,
I think you need to make the timer handler be an async method as follows:
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
await getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
This way OnPropertyChanged("Friends") is guaranteed to fire after the work in getMessages is done.
The methods need to change to:
DispatcherTimer _timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
public async void timerchat_Tick(object sender, EventArgs e)
{
//...
await getMessages();
//...
}
public async Task getMessages()
{
try
{
// ... your code here
string result = await response.Content.ReadAsStringAsync();
// .... rest of your code
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
}
}
It is solved. The problem was in my ViewModels I was opening multiple threads and sometimes the right one would update the UI and sometimes no.
Thanks for all the answers.
I'm facing a bit of problem, it's giving error "Cross-thread operation not valid" even though I'm using Invoke method.
Here's the code snipit.
Method to update log box
private void updateStatus(String msg)
{
if (logBox.InvokeRequired)
logBox.Invoke((MethodInvoker)delegate()
{
logBox.SelectionStart = logBox.Text.Length;
logBox.Text += "\n";
logBox.Text += msg;
});
else
logBox.SelectionStart = logBox.Text.Length;
logBox.Text += "\n";
logBox.Text += msg;
}
And this Run method is being run by a thread.
private void Run()
{
int port;
try
{
port = Int32.Parse(broadcastPortTextBox.Text);
}
catch (Exception ex)
{
MetroFramework.MetroMessageBox.Show(this, ex.Message);
return;
}
updateStatus("Starting server at port: " + port.ToString());
server = new HTTPServer.HTTPServer(port);
server.Start();
} //function
It runs fine for the first time but when I click stop, it gives an exception.
private void stopButton_Click(object sender, EventArgs e)
{
updateStatus("Stoping server");
th.Abort();
updateStatus("Server stoped!");
}
I would try using the direct cast for the invoke. There's no need to check whether the invoke is required or not. If you invoke something it should always happen (in your context). Just remove the updateStatus(String msg) method so and try to cast your update like this:
void Run() {
// stuff
broadcastPortTextBox.Invoke(() => {
port = Int32.Parse(broadcastPortTextBox.Text);
});
// stuff..
logBox.Invoke(() => {
logBox.SelectionStart = logBox.Text.Length;
logBox.Text += string.Format("{0}{1}", Environment.NewLine, "Your message text..");
});
// stuff..
}
Note: If you manipulate any non thread owned element use the invoke method. Otherwise you'll end up with exceptions (see 'broadcastPortTextBox');
Edit: Accidently saved before I was done.
So I am trying to create a basic WinForm Application that uses SNMP, from snmpsharpnet.
I have two buttons 'Eye' and 'Jitter' that when one is pressed a timer starts which executes SNMP code inside the timer handler every minute.
I am trying to write the SNMP output to a textbox from the timer handler but everything I try either leads to thread exceptions or a continuous running process when I exit the program.
I have tried so many different things to fix those two errors that I may be screwing everything up but here is the code I have:
using System;
using System.Net;
using SnmpSharpNet;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public static bool stop = false;
static bool min = false, sec = false, eye = false, jitter = false;
static string ipAdd = "";
static System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
static int alarmCounter = 1;
static bool exitFlag = false;
static TextBox textbox;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
textbox = outputBox;
}
private void IPtext_TextChanged(object sender, EventArgs e)
{
ipAdd = IPtext.Text;
}
private void stopButton_Click(object sender, EventArgs e)
{
stop = true;
timer.Stop();
}
// This is the method to run when the timer is raised.
private static void TimerEventProcessor(Object myObject,
EventArgs myEventArgs)
{
timer.Stop();
// If stop button has not been pressed then continue timer.
if (stop == false)
{
textbox.Clear();
// Restarts the timer and increments the counter.
alarmCounter += 1;
timer.Enabled = true;
/*
textbox.Invoke(
new MethodInvoker(
delegate { textbox.AppendText("fsjdaò"); }));
*/
System.IO.StreamWriter file;
if (eye == true)
{
file = new System.IO.StreamWriter("c:/Users/bshellnut/Desktop/Eye.txt", true);
}
else
{
file = new System.IO.StreamWriter("c:/Users/bshellnut/Desktop/Jitter.txt", true);
}
// SNMP community name
OctetString community = new OctetString("public");
// Define agent parameters class
AgentParameters param = new AgentParameters(community);
// Set SNMP version to 2 (GET-BULK only works with SNMP ver 2 and 3)
param.Version = SnmpVersion.Ver2;
// Construct the agent address object
// IpAddress class is easy to use here because
// it will try to resolve constructor parameter if it doesn't
// parse to an IP address
IpAddress agent = new IpAddress(ipAdd);
// Construct target
UdpTarget target = new UdpTarget((IPAddress)agent, 161, 2000, 1);
// Define Oid that is the root of the MIB
// tree you wish to retrieve
Oid rootOid;
if (eye == true)
{
rootOid = new Oid("1.3.6.1.4.1.128.5.2.10.14"); // ifDescr
}
else
{
rootOid = new Oid("1.3.6.1.4.1.128.5.2.10.15");
}
// This Oid represents last Oid returned by
// the SNMP agent
Oid lastOid = (Oid)rootOid.Clone();
// Pdu class used for all requests
Pdu pdu = new Pdu(PduType.GetBulk);
// In this example, set NonRepeaters value to 0
pdu.NonRepeaters = 0;
// MaxRepetitions tells the agent how many Oid/Value pairs to return
// in the response.
pdu.MaxRepetitions = 5;
// Loop through results
while (lastOid != null)
{
// When Pdu class is first constructed, RequestId is set to 0
// and during encoding id will be set to the random value
// for subsequent requests, id will be set to a value that
// needs to be incremented to have unique request ids for each
// packet
if (pdu.RequestId != 0)
{
pdu.RequestId += 1;
}
// Clear Oids from the Pdu class.
pdu.VbList.Clear();
// Initialize request PDU with the last retrieved Oid
pdu.VbList.Add(lastOid);
// Make SNMP request
SnmpV2Packet result;
try
{
result = (SnmpV2Packet)target.Request(pdu, param);
//textbox.Text = "";
}
catch (SnmpSharpNet.SnmpException)
{
textbox.Invoke(
new MethodInvoker(
delegate { textbox.AppendText("Could not connect to the IP Provided."); }));
timer.Stop();
//outputBox.Text += "Could not connect to the IP Provided.";
break;
}
// You should catch exceptions in the Request if using in real application.
// If result is null then agent didn't reply or we couldn't parse the reply.
if (result != null)
{
// ErrorStatus other then 0 is an error returned by
// the Agent - see SnmpConstants for error definitions
if (result.Pdu.ErrorStatus != 0)
{
// agent reported an error with the request
/*Console.WriteLine("Error in SNMP reply. Error {0} index {1}",
result.Pdu.ErrorStatus,
result.Pdu.ErrorIndex);*/
textbox.Invoke(
new MethodInvoker(
delegate { textbox.AppendText("Error in SNMP reply. " + "Error " + result.Pdu.ErrorStatus + " index " + result.Pdu.ErrorIndex); }));
//outputBox.Text = "Error in SNMP reply. " + "Error " + result.Pdu.ErrorStatus + " index " + result.Pdu.ErrorIndex;
lastOid = null;
break;
}
else
{
// Walk through returned variable bindings
foreach (Vb v in result.Pdu.VbList)
{
// Check that retrieved Oid is "child" of the root OID
if (rootOid.IsRootOf(v.Oid))
{
/*Console.WriteLine("{0} ({1}): {2}",
v.Oid.ToString(),
SnmpConstants.GetTypeName(v.Value.Type),
v.Value.ToString());*/
textbox.Invoke(
new MethodInvoker(
delegate { textbox.AppendText(v.Oid.ToString() + " " + SnmpConstants.GetTypeName(v.Value.Type) +
" " + v.Value.ToString() + Environment.NewLine); }));
//outputBox.Text += v.Oid.ToString() + " " + SnmpConstants.GetTypeName(v.Value.Type) +
//" " + v.Value.ToString() + Environment.NewLine;
file.WriteLine(v.Oid.ToString() + " " + SnmpConstants.GetTypeName(v.Value.Type) +
" " + v.Value.ToString(), true);
if (v.Value.Type == SnmpConstants.SMI_ENDOFMIBVIEW)
lastOid = null;
else
lastOid = v.Oid;
}
else
{
// we have reached the end of the requested
// MIB tree. Set lastOid to null and exit loop
lastOid = null;
}
}
}
}
else
{
//Console.WriteLine("No response received from SNMP agent.");
textbox.Invoke(
new MethodInvoker(
delegate { textbox.AppendText("No response received from SNMP agent."); }));
//outputBox.Text = "No response received from SNMP agent.";
}
}
target.Close();
file.Close();
}
else
{
// Stops the timer.
exitFlag = true;
}
}
private void eyeButton_Click(object sender, EventArgs e)
{
outputBox.Text = "Connecting...";
eye = true;
jitter = false;
stop = false;
timer.Tick += new EventHandler(TimerEventProcessor);
// Sets the timer interval to 5 seconds.
timer.Interval = 5000;
timer.Start();
// Runs the timer, and raises the event.
while (exitFlag == false)
{
// Processes all the events in the queue.
Application.DoEvents();
}
}
private void jitterButton_Click(object sender, EventArgs e)
{
outputBox.Text = "Connecting...";
eye = false;
jitter = true;
stop = false;
timer.Tick += new EventHandler(TimerEventProcessor);
// Sets the timer interval to 5 seconds.
timer.Interval = 5000;
timer.Start();
// Runs the timer, and raises the event.
while (exitFlag == false)
{
// Processes all the events in the queue.
Application.DoEvents();
}
}
private void Seconds_CheckedChanged(object sender, EventArgs e)
{
min = false;
sec = true;
}
private void Minutes_CheckedChanged(object sender, EventArgs e)
{
min = true;
sec = false;
}
}
}
I believe you are running into a deadlock on the UI thread.
TimerEventProcessor() is called by your instance of System.Windows.Forms.Timer, which runs on the UI thread. When the timer goes off, I believe it puts a message into the UI thread's message queue to call your TimerEventProcessor() method. That method in turn calls textbox.Invoke(), which puts another message into the queue and then waits for it to be processed.
Your UI thread is now stuck, as it is in the middle of processing a message, but must wait until another message is processed before it can continue. The calls to Application.DoEvents() do you no good, as they are not being called once your program enters TimerEventProcessor(). (They're also unnecessary, since your button click handlers wouldn't be blocking the UI thread anyway.)
Since the timer runs on the UI thread, you can get rid of the textbox.Invoke() calls and just access textbox directly.
Summary:
Replace your calls to textbox.Invoke() with direct access to textbox
Remove your calls to Application.DoEvents()
Note: if you got the Application.DoEvents() logic from the MSDN example for using a timer, they put it there so that the application doesn't quit once the Main function completes.
Update: You can see if this is truly the issue by replacing your calls to textbox.Invoke with the following code. If this code works, then you definitely have a UI message queue deadlocking issue. Also, if this does resolve the issue, I would not recommend keeping this as the solution, but rather, addressing the deadlocking as suggested above.
// Make the request asynchronously
System.IAsyncResult asyncResult = textbox.BeginInvoke(
new MethodInvoker(
delegate { /* insert delegate code here */ }));
// Process the message queue until this request has been completed
while(!asyncResult.IsCompleted) Application.DoEvents();
// Clean up our async request
textbox.EndInvoke(asyncResult);
Since you seem to have your code working, you can ignore the above test code.
Your problem is not related to the timer and all the Invoke statements you use are not necessary. The System.Windows.Forms.Timer class operates in the UI thread. Look here: http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx