Detect if a conversation is incoming or outgoing - c#

I use the Lync SDK 2013 and try to check if a new conversation is incoming or outgoing. I don't want to check for audio/video calls only, I want to check in on each modality type.
private void Conversation_Added(object sender, ConversationManagerEventArgs e)
{
Conversation conversation = e.Conversation;
IDictionary<ModalityTypes, Modality> modalities = conversation.Modalities;
bool conversationIsIncoming = modalities.Any(modality => modality.Value.State == ModalityState.Notified);
}
When the event gets triggered and it comes to the Any method I get this error
NullReferenceException object reference not set to an instance of an object.
System.Collections.Generic.KeyValuePair.Value.get
returned null.
So obviously I have to use a null check here but maybe the whole code may be wrong? How can I check if the conversation is incoming or outgoing?

Your idea is basically correct but when you check for the notified state is incorrect.
You need to hook the ModalityStateChanged event, and if you only want to know about audio/video "Calls" then you also only need to hook for conversations that have AudioVideo modality type.
e.g.
private void ConversationManager_ConversationAdded(object sender, ConversationManagerEventArgs e)
{
if (e.Conversation.Modalities.TryGetValue(ModalityTypes.AudioVideo, out var avModality))
{
avModality.ModalityStateChanged += AvModalityOnStateChanged;
}
}
private void AvModalityOnStateChanged(object sender, ModalityStateChangedEventArgs e)
{
if (e.NewState == ModalityState.Notified)
{
bool conversationIsIncoming = true;
}
}
Don't forget to unhook from the ModalityStateChanged when you don't need to know the state change any longer.

Related

Cannot write to Unity's TMPro text field after getting data from Realtime Database in Firebase

I am attempting to pull data from my Realtime Database in Firebase and then put that string into a TMP_Text field in unity.
There seems to be an issue with writing to a text field while within the .ContinueWith(task => portion of my code. While inside the task.isCompleted I can get the snapshot print the value after converting it to string, however, as soon as I try to write to the text field the code haults. In the example below the output is as follows.
Prints the snapshot, both key and value
Prints the value of the snapshot as a string
No errors no thing happens
The 4th print of Value does not print at all
public void PopulateScoreBoard()
{
FirebaseDatabase.DefaultInstance.GetReference("userlist").Child(LoadingScreen.userID).Child("score").GetValueAsync().ContinueWith(task =>
{
if (task.IsFaulted)
{
//handle error
scoreboard.text = "Error!";
}
else if (task.IsCompleted)
{
//get snapshot fo data
DataSnapshot snapshot = task.Result;
print(snapshot);
print(snapshot.Value.ToString());
//Get the scoreboard value within the result snapshot
scoreboard.text = snapshot.Value.ToString();
//print the same value to ensure it is working
print(snapshot.Value.ToString());
}
});
}
Looking forward to getting some input, I'm assuming there is some reason you cannot write to anything in this, however, I cannot find it. If this is the case what is my alternative?
*Update: It seems as though after further testing you cannot set anything equal to anything inside the ContinueWith(task => is that normal?
I was able to find an answer but I would still love some input to see if I am doing it right.
I changed to this code and it seems to be working fine.
public void loadData()
{
FirebaseDatabase.DefaultInstance.GetReference("userlist").ValueChanged += Script_ValueChanged;
}
private void Script_ValueChanged(object sender, ValueChangedEventArgs e)
{
scoreboard.text = e.Snapshot.Child(LoadingScreen.userID).Child("userScore").GetValue(true).ToString();
}
And then called it at start.
First, I think you could fix your initial issue by replacing ContinueWith with ContinueWithOnMainThread:
public void PopulateScoreBoard()
{
FirebaseDatabase.DefaultInstance.GetReference("userlist").Child(LoadingScreen.userID).Child("score").GetValueAsync().ContinueWithOnMainThread(task =>
{
if (task.IsFaulted)
{
//handle error
scoreboard.text = "Error!";
}
else if (task.IsCompleted)
{
//get snapshot fo data
DataSnapshot snapshot = task.Result;
print(snapshot);
print(snapshot.Value.ToString());
//Get the scoreboard value within the result snapshot
scoreboard.text = snapshot.Value.ToString();
//print the same value to ensure it is working
print(snapshot.Value.ToString());
}
});
}
The reason is that ContinueWith will return in the background. Then you perform the non-thread-safe operation scoreboard.text = "Error!";, which will cause something in the range of an exception to a crash. There's an article I wrote about this here.
Now, your answer is more correct. GetDataAsync will register a ValueChanged listener, wait for a result, and then unregister this listener. The problem is that this means that if you have stale data in your cache, your GetValueAsync will be the last value retrieved from the Firebase backend rather than the latest data.
Looking at your code, the only thing you should do different is cache the "userlist" reference and unregister later. This has to do with how Unity handles memory and object lifetime - it would be possible in your code for the text to be set on a null object:
private DatabaseReference _userListReference;
void Start() {
_userListReference = FirebaseDatabase.DefaultInstance.GetReference("userlist");
_userListReference.ValueChanged += Script_ValueChanged;
}
void OnDestroy() {
_userListReference.ValueChanged -= Script_ValueChanged;
}
private void Script_ValueChanged(object sender, ValueChangedEventArgs e)
{
scoreboard.text = e.Snapshot.Child(LoadingScreen.userID).Child("userScore").GetValue(true).ToString();
}
Due to a current bug, you MUST cache the reference to remove the event listener. If you try to retrieve it again with GetReference, you'll make a second C# copy of the underlying object and the event listener will live on.

can not hit the SerialDataReceivedEvent?

All these comes from the idea that i want to use the SerialPort class in .Net , but the only way is by calling dll . Because i can only get interfaces from the program calling this dll. mycode is below.
i wrote a class about serialport,
public class CommClass
{
public SerialPort _port;
private string _receivedText;
public string receivedText
{
get { return _receivedText; }
set
{
_receivedText = value;
}
}
public CommClass(string _pname)
{
portList = SerialPort.GetPortNames();
_port = new SerialPort(portList[0]);
if (portList.Length < 1)
_port= null;
else
{
if(portList.Contains(_pname.ToUpper()))
{
_port = new SerialPort(_pname);
_port.DataReceived += new SerialDataReceivedEventHandler(com_DataReceived);
}
}
}
private void com_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string indata = _port.ReadExisting();
receivedText = indata;
}
}
from Bytestoread i can see there r data coming in and i can get data from port.ReadExisting(), but receivedText did not change ,it did not hit the SerialDataReceived event . Is my way wrong?any suggestion?thanks
i created a dll from CommClass ,then i call it in my winform program which has a button and a textbox . Clicking the button , then i initialize the port
public Form1()
{
InitializeComponent();
}
public CommClass mycom;
private void button1_Click(object sender, EventArgs e)
{
mycom = new CommClass("com3");
mycom._port.Open();
textbox.Text=mycom.receivedText;//i add a breakpoint at this line ,
}
when hitting it , i check mycom._port.PortName is "com3", its IsOpen() is "Open" , i use virtual port to send data . i send "1111",then check the mycom._port.BytestoRead is 4, and mycom._port.ReadExisting() is "1111", but mycom.receivedText is null. My puzzle is that i have no idea when the data is coming . How to use the DataReceived event in my winform without code "using System.Io.Ports",just with reference CommClass.dll. Did i make it clear? Thanks for help.
mycom._port.Open();
textbox.Text=mycom.receivedText;//i add a breakpoint at this line ,
That code cannot work, it is a threading race bug. The DataReceived event does not fire instantly after you open the port. It will take a microsecond or so, give or take. A threadpool thread has to get started to fire the event. And of course the device actually has to send something, they usually only do so when you transmit something first.
Which clearly did not happen, your DataReceived event handler has a bug as well. It is not allowed to update the Text property of a control in that event since it runs on a worker thread. Your program will bomb with an InvalidOperationException.
You'll have to write something like this instead:
private void com_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string indata = _port.ReadExisting();
this.BeginInvoke(new Action(() => {
textbox.AppendText(indata);
}));
}
With the additional stipulation that you must not leave it this way, updating the Text property of a TextBox and making it visible on the screen is an expensive operation that's going to turn your user interface catatonic when the device starts transmitting data at a high rate.

Statement performed only when method ends

I'm C# with Compact Framework and I realized something weird today. I'm calling a method by an event that applies a set to an object and when I debug, it passes by this, but just performs after the last close bracket of the method. My example:
public string Loading
{
set { lblLoading.Text = value; }
}
private void btnAuth_Click(object sender, EventArgs e)
{
Loading = "Loading...";
_presenter.PerformAuth();
}
When I debug, it passes by my first statement, applies it, but doesn't change anything on the screen... Oh, until it do PerformAuth(). After it, so, then the label value is changed. Oh, the problem isn't just by it be synchronous. The same occurs when I try to do an asynchronous task:
private void btnAuth_Click(object sender, EventArgs e)
{
ASyncResult res = BeginInvoke(new Action(() =>Loading = "Loading..."));
EndInvoke(res);
_presenter.PerformAuth();
}
I think it might be a bug in thread and in C# design implementation. And also with direct set it is stubborn to me. As you can see in the image below:
I just want to set a text in a label, call a method and unset it in an event. Why does C# get it so complicated?

Trouble with raising custom event handling between 2 forms

New to C#. Like the title, I'm having difficulty trying to raise an event. It will eventually then be consumed on another form.
What I'm trying to do is have many instances of a custom user control (my event raising form(s)) that creates a tcp client, connects, and then closes. When this tcp client has an "error", be it a catch exception, I want an event to be raised. I'm forcing the error right now by having my internet turned off to test. My first problem is I can't even get the event to be raised at all. I'll show the event code I'm working with on my custom user control:
public delegate void TaskCompleteEventHandler(object sender, TaskCompleteEventArgs e);
public event TaskCompleteEventHandler TaskComplete;
public class TaskCompleteEventArgs : System.EventArgs
{
// add local member variables to hold text
private string errorString;
// class constructor
public TaskCompleteEventArgs(string ErrorString)
{
this.errorString = ErrorString;
}
// Property
public string ErrorString
{
get
{
return errorString;
}
set
{
errorString = value;
}
}
}
This is my method that processes the exception and ideally would raise the event and allow the host form to print the string and exception accordingly.
private void ErrorLogging(string ex)
{
errorString = String.Format(/*...errorString formatting...*/);
// instance the event args and pass it the errorString value
TaskCompleteEventArgs args = new TaskCompleteEventArgs(errorString);
// raise the event with the updated arguments
TaskComplete(this, args); //----> THIS IS WHERE I GET AN ERROR!! <----
this.Dispose();
}
The error is Object reference not set to an instance of an object.
Here's the Watch screen of my TaskComplete(this, args)
I can't seem to debug this... I'm just not strong enough yet to know what I've done wrong. How is it causing side effects?
I'm sure I'm going to have more issues on my main form when I get this going... Does anyone have a clue what's causing this? Thanks in advance.
EDIT: On my main form:
public Form1()
{
InitializeComponent();
// Start control disabled and subscribe each control the event
foreach (var control in controlList)
{
control.Enabled = false;
control.TaskComplete += new dev_emu_project.dev_emu_widget.TaskCompleteEventHandler(OnTaskComplete);
}
}
List<dev_emu_project.dev_emu_widget> controlList = new List<dev_emu_project.dev_emu_widget>();
public void OnTaskComplete(object sender, dev_emu_project.TaskCompleteEventArgs e)
{
//.... work for processing
}
}
You are getting a NullReferenceException because you're invoking an empty event, meaning no delegate has been registered to it. You need to make sure TaskComplete isn't null before invoking it.
Add a null check before invoking to make sure someone did register to your event:
if (TaskComplete != null)
{
TaskComplete(this, args);
}
From MSDN Event Tutorial:
Invoking an event
Once a class has declared an event, it can treat that event just like a field of the indicated delegate type. The field will either be null, if no client has hooked up a delegate to the event, or else it refers to a delegate that should be called when the event is invoked. Thus, invoking an event is generally done by first checking for null and then calling the event

Serial IO Async Issues

I've got serial data coming in to my application and by definition, it's async, so I'm running into troubles when trying to update a label to show what the incoming data is. Every now and then, I get an error on the lblRx.AsyncUpdate line, telling me the object is in use elsewhere.
At present, I use the following code;
private void IODataReceived(object sender, IODataEventArgs e)
{
lblRx.AsyncUpdate(() => lblRx.Text = string.Format("{0}:\t{1}", e.Timestamp, e.Data));
SetBackColors(false, eIODirection.In);
}
public static void AsyncUpdate(this Control ctrl, ActionCallback action)
{
if (ctrl != null)
{
if (!ctrl.IsHandleCreated && ctrl.IsDisposed)
ctrl.CreateControl(); // MSDN says CreateControl() is preferred over CreateHandle().
if (!ctrl.IsDisposed)
AsyncInvoke(ctrl, action);
}
}
The AsyncUpdate method isn't an issue (AFAIK...works well in other situations).
I think I need to put a lock on the control before calling AsyncUpdate. Or is there a better way to handle this situation?

Categories

Resources