I'm using Unity Ads in my game. In older version i check if unity video ads are ready to show then call a method to show ads like this
public bool IsVideoReady()
{
if (Advertisement.IsReady())
return true;
else
return false;
}
But in new version i dont know how to check if unity video ads are ready or loaded to show.
My new script is
using UnityEngine;
using UnityEngine.Advertisements;
public class AdsInitializer : MonoBehaviour, IUnityAdsInitializationListener, IUnityAdsLoadListener, IUnityAdsShowListener
{
[SerializeField] string _androidGameId;
[SerializeField] string _iOSGameId;
string _gameId;
[SerializeField] bool _testMode = true;
private void Awake()
{
if (Advertisement.isInitialized)
{
Debug.Log("Advertisement is Initialized");
LoadRewardedAd();
}
else
{
InitializeAds();
}
}
public void InitializeAds()
{
_gameId = (Application.platform == RuntimePlatform.IPhonePlayer) ? _iOSGameId : _androidGameId;
Advertisement.Initialize(_gameId, _testMode, this);
}
public void OnInitializationComplete()
{
Debug.Log("Unity Ads initialization complete.");
LoadInerstitialAd();
LoadBannerAd();
}
public void OnInitializationFailed(UnityAdsInitializationError error, string message)
{
Debug.Log($"Unity Ads Initialization Failed: {error.ToString()} - {message}");
}
public void LoadInerstitialAd()
{
Advertisement.Load("Interstitial_Android", this);
}
public void LoadRewardedAd()
{
Advertisement.Load("Rewarded_Android", this);
}
public void OnUnityAdsAdLoaded(string placementId)
{
Debug.Log("OnUnityAdsAdLoaded");
Advertisement.Show(placementId,this);
}
public void OnUnityAdsFailedToLoad(string placementId, UnityAdsLoadError error, string message)
{
Debug.Log($"Error showing Ad Unit {placementId}: {error.ToString()} - {message}");
}
public void OnUnityAdsShowFailure(string placementId, UnityAdsShowError error, string message)
{
Debug.Log("OnUnityAdsShowFailure");
}
public void OnUnityAdsShowStart(string placementId)
{
Debug.Log("OnUnityAdsShowStart");
Time.timeScale = 0;
Advertisement.Banner.Hide();
}
public void OnUnityAdsShowClick(string placementId)
{
Debug.Log("OnUnityAdsShowClick");
}
public void OnUnityAdsShowComplete(string placementId, UnityAdsShowCompletionState showCompletionState)
{
Debug.Log("OnUnityAdsShowComplete "+showCompletionState);
if (placementId.Equals("Rewarded_Android") && UnityAdsShowCompletionState.COMPLETED.Equals(showCompletionState))
{
Debug.Log("rewared Player");
}
Time.timeScale = 1;
Advertisement.Banner.Show("Banner_Android");
}
public void LoadBannerAd()
{
Advertisement.Banner.SetPosition(BannerPosition.BOTTOM_CENTER);
Advertisement.Banner.Load("Banner_Android",
new BannerLoadOptions
{
loadCallback = OnBannerLoaded,
errorCallback = OnBannerError
}
);
}
void OnBannerLoaded()
{
Advertisement.Banner.Show("Banner_Android");
}
void OnBannerError(string message)
{
}
}
i just want to know how to check if unity interstital or rewarded ads are ready before showing them.
because in new versions Advertisment.isReady() is not working any more
I'm using Unity Mirror for networking my app so that a central server (not host) can send commands to the clients it is connected to.
On play, the "game" will make the program a client or server automatically on play, so i don't have to use the Client/Server only buttons provided by the NetworkManagerHUD.
Currently I'm facing 2 problems:
Client disconnects right after a connection with server is made. When I override the OnClientConnect function, I put the line base.OnClientConnect(conn). After stepping into the original function, I conclude it is the autoCreatePlayer set to true that is causing this problem. (the server and client are two instances of the program running on the same computer as I can only test using localhost).
public override void OnClientConnect(NetworkConnection conn)
{
base.OnClientConnect(conn); //This line causes the error message
clientConnected = true;
GameObject[] prefabs = Resources.LoadAll<GameObject>("NetworkingComponents");
foreach (var prefab in prefabs)
{
NetworkClient.RegisterPrefab(prefab);
}
GameObject[] gos = Resources.LoadAll<GameObject>("NetworkingComponents");
}
Perhaps the most critical issue. Referring to the previous problem, if i did remove the line
base.OnClientConnect(conn), client can connect, but all networked gameobjects (with NetworkIdentity) are still not showing up when connected as client, even though the NetworkManagerHUD says the program is connected as client. (Strangely, they are showing up if connected as Server.)
Here is the rest of the overriden NetworkManager code.
public class MyNetworkManager : NetworkManager
{
public GameObject dropdown;
public Canvas canvas;
//---------------------------Networking stuff----------------------------------
public List<NetworkNode> networkedNodes { get; } = new List<NetworkNode>();
public List<Settings> networkedSettings { get; } = new List<Settings>();
public List<NetworkedVisualisersDisplay> visualisersDisplays { get; } = new List<NetworkedVisualisersDisplay>();
public List<Visualiser> visualisers{ get; } = new List<Visualiser>();
public static MyNetworkManager instance = null;
public NetworkedVisualisersDisplay visDisplayPrefab;
public NetworkNode networkNode;
private string homeName;
public volatile bool clientConnected = false;
public bool IsClientConnected()
{
return clientConnected;
}
//the purpose of having a delay is that we need to determine if the call to StartClient() actually started the player as a client. It could fail if it’s the first player instance on the network.
public IEnumerator DelayedStart()
{
//base.Start();
StartClient();
yield return new WaitForSeconds(2);
print("conn count " + NetworkServer.connections.Count);
if (!IsClientConnected())
{
NetworkClient.Disconnect();
print(“starting as server”);
StartServer();
clientConnected = false;
}
else
{
print("starting as client");
}
visDisplayPrefab = Resources.Load<NetworkedVisualisersDisplay>("NetworkingComponents/NetworkedVisualisersDisplay");
if (instance == null)
{
instance = this;
print("instance = " + this);
}
else
{
print("manager destroyed");
Destroy(gameObject);
}
yield return null;
}
//-----------------------------------------------------------------------------
public override void Start(){
StartCoroutine(DelayedStart());
}
public override void OnStartServer()
{
GameObject[] prefabs = Resources.LoadAll<GameObject>("NetworkingComponents");
foreach (var prefab in prefabs)
{
spawnPrefabs.Add(prefab);
}
}
public override void OnServerChangeScene(string scenename)
{
if (scenename.Equals("Visualisers"))
{
for (int i = 0; i < visualisersDisplays.Count; i++)
{
var conn = networkedNodes[i].connectionToClient;
NetworkedVisualisersDisplay visSceneInstance = Instantiate(visualisersDisplays[i]);
NetworkServer.Destroy(conn.identity.gameObject);
NetworkServer.ReplacePlayerForConnection(conn, visSceneInstance.gameObject);
}
}
else if (Settings.Instance.sceneNames.Contains(scenename))
{
for (int i = 0; i < visualisersDisplays.Count; i++)
{
var conn = visualisers[i].connectionToClient;
var visInstance = Instantiate(visualisers[i]);
NetworkServer.Destroy(conn.identity.gameObject);
NetworkServer.ReplacePlayerForConnection(conn, visInstance.gameObject);
}
}
}
public override void OnServerAddPlayer(NetworkConnection conn)
{
NetworkNode n = Instantiate(networkNode);
NetworkServer.AddPlayerForConnection(conn, n.gameObject);
NetworkNode.instance.DisplayMessage();
}
public override void OnClientConnect(NetworkConnection conn)
{
base.OnClientConnect(conn);
//we are connected as a client
clientConnected = true;
GameObject[] prefabs = Resources.LoadAll<GameObject>("NetworkingComponents");
foreach (var prefab in prefabs)
{
NetworkClient.RegisterPrefab(prefab);
}
}
}
Any help will be greatly appreciated!
I am using admob ads in my app and they are working fine. But when i try to do something after a ad close or reward earned call back my code breaks. Following is my adMob script
public class AdMobScript : MonoBehaviour
{
...
public event Action OnReviveRewardEarned;
public event Action OnReviveAdLoaded;
public event Action OnReviveAdClosed;
private void LoadReviveRewardedAd()
{
reviveRewardedAd = new RewardedAd(adReviveRewardedId);
reviveRewardedAd.OnAdLoaded += ReviveAdLoaded;
reviveRewardedAd.OnUserEarnedReward += ReviveEarnedReward;
reviveRewardedAd.OnAdClosed += ReviveAdClosed;
AdRequest request = new AdRequest.Builder().Build();
reviveRewardedAd.LoadAd(request);
}
private void ReviveAdClosed(object sender, EventArgs e)
{
LoadReviveRewardedAd();
if (isRewardErned)
{
isRewardErned = false;
OnReviveRewardEarned.Invoke();
}
else
OnReviveAdClosed.Invoke();
}
private void ReviveEarnedReward(object sender, Reward e)
{
isRewardErned = true;
}
private void ReviveAdLoaded(object sender, EventArgs e)
{
//reviveButton.interactable = true;
OnReviveAdLoaded.Invoke();
}
public void ShowAdToRevive()
{
if (reviveRewardedAd.IsLoaded())
{
reviveRewardedAd.Show();
}
}
...
}
In the callbacks i am calling my adManager script which is in term using adMob script. Here is the code for it.
public class AdManager : MonoBehaviour
{
...
private void Start() {
AdMobScript.instance.OnReviveAdClosed += ReviveAdClosed;
AdMobScript.instance.OnReviveAdLoaded += ReviveAdLoaded;
AdMobScript.instance.OnReviveRewardEarned += ReviveReward;
}
#region ReviveAds
private void ReviveReward() {
//game crash here
backButton.gameObject.SetActive(true);
reviveButton.gameObject.SetActive(false);
noThanksButton.gameObject.SetActive(false);
manager.Revive();
}
private void ReviveAdLoaded() {
reviveButton.interactable = true;
}
private void ReviveAdClosed() {
//game crash here
reviveButton.interactable = false;
}
public void ShowAdToRevive() {
AdMobScript.instance.ShowAdToRevive();
}
...
}
After either ad close or reward earned my game crashes (error log says
get_gameObject can only be called from the main thread
). There must be something i am doing wrong. Can anyone please point me to the right direction?
The reason for the problem - you trying to manipulate with MonoBehaviors, not in main thread.
Just write simple scheduler which calls the events in the Unity thread, like this:
Scheduler:
using System;
using UnityEngine;
public class Scheduler : MonoBehaviour
{
public static Scheduler instance;
public event Action secondTick = delegate { };
private float seconds = 0;
private void Awake()
{
instance = this;
}
private void Update()
{
seconds += Time.unscaledDeltaTime;
if (seconds >= 1.0f)
{
seconds -= 1.0f;
secondTick.Invoke();
}
}
}
Updated AdMobScript:
public class AdMobScript : MonoBehaviour
{
...
private bool onRewardEarnedCall = false;
private bool onRewardAdLoaded = false;
private bool onRewardAdClosed = false;
public event Action OnReviveRewardEarned;
public event Action OnReviveAdLoaded;
public event Action OnReviveAdClosed;
private void LoadReviveRewardedAd()
{
reviveRewardedAd = new RewardedAd(adReviveRewardedId);
reviveRewardedAd.OnAdLoaded += ReviveAdLoaded;
reviveRewardedAd.OnUserEarnedReward += ReviveEarnedReward;
reviveRewardedAd.OnAdClosed += ReviveAdClosed;
AdRequest request = new AdRequest.Builder().Build();
reviveRewardedAd.LoadAd(request);
Scheduler.instance.secondTick += OnSecondTick;
}
private void OnSecondTick()
{
if(onRewardAdClosed)
{
onRewardAdClosed = false;
OnReviveAdClosed.Invoke();
}
if(onRewardEarnedCall)
{
OnReviveRewardEarned.Invoke();
onRewardEarnedCall = false;
}
if(onRewardAdLoaded)
{
OnReviveAdLoaded.Invoke();
onRewardAdLoaded = false;
}
}
private void ReviveAdClosed(object sender, EventArgs e)
{
LoadReviveRewardedAd();
if (isRewardErned)
{
isRewardErned = false;
onRewardEarnedCall = true;
}
else
onRewardAdClosed = true;
}
private void ReviveEarnedReward(object sender, Reward e)
{
isRewardErned = true;
}
private void ReviveAdLoaded(object sender, EventArgs e)
{
//reviveButton.interactable = true;
onRewardAdLoaded = true;
}
public void ShowAdToRevive()
{
if (reviveRewardedAd.IsLoaded())
{
reviveRewardedAd.Show();
}
}
...
}
This is a very simple and not optimize solution but this will solve your problem.
I am working on a UCMA 3.0 workflow application and am attempting to generate queries into our client management system allowing end users to obtain data about specific clients via voice or instant message. I was wondering anyone knows how to create a generic questionanswer activity using UCMA that allows generic input. I know that I can set up expected inputs and grammars, but with the bi-capitalization options, and the likelihood that an end user would know the exact client name (or client number for that matter), I would prefer to allow the user to enter part of the name and then search the database for a list of names that might meet the criteria. Does anyone know of a way, and have sample code that might allow me to do this if it is possible?
I had the same problem and had to write a custom activity to capture generic input from a user. This needs some work to make it production ready. Note the classy catching of system.exception in multiple places, as well as throwing an exception if input isn't received within the timeout period instead of reprompting the user. Also no regex on the user input...
The InstanceDependencyProperty is something else that was frustrating about Workflow. Without using InstanceDependencyProperties you won't be able to retrieve any results after the activity is completed.
Hope this helps!
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using Microsoft.Rtc.Collaboration;
using Microsoft.Rtc.Workflow.Activities;
using Microsoft.Rtc.Workflow.Common;
namespace ActivityLibrary
{
public partial class CaptureIMInput : Activity, IInstanceDependencyContainer
{
#region Private member variables
private CallProvider _callProvider;
private Timer _maximumTimer;
private string _imText;
private bool messageReceived = false;
private bool _maximumTimerElapsed = false;
#endregion
public CaptureIMInput()
{
InitializeComponent();
_instanceDependencyProperties = new Dictionary<string, object>();
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
try
{
this._callProvider = Utilities.GetCallProviderFromParent<InstantMessagingCall>(this);
InstantMessagingCall call = (InstantMessagingCall)this._callProvider.Call;
try
{
if (call.State == CallState.Established)
{
call.Flow.EndSendInstantMessage(call.Flow.BeginSendInstantMessage(MainPrompt, null, null));
_maximumTimer = new Timer(new TimerCallback(OnMaximumTimerFired), null, MaximumPrompt, new TimeSpan(0, 0, 0, 0, -1));
call.Flow.MessageReceived += this.InstantMessagingFlow_MessageReceived;
while (!messageReceived)
{
if (_maximumTimerElapsed)
throw new TimeoutException("User input was not detected within alloted time");
}
if (!string.IsNullOrEmpty(_imText))
{
IMText = _imText;
{
this.Stop();
return ActivityExecutionStatus.Closed;
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
catch (Exception ex)
{
throw ex;
}
return ActivityExecutionStatus.Closed;
}
protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext)
{
this.Stop(); //Clean up timer
return ActivityExecutionStatus.Canceling;
}
private void Stop()
{
if (_maximumTimer != null)
{
_maximumTimer.Dispose();
_maximumTimer = null;
}
}
private void InstantMessagingFlow_MessageReceived(object sender, InstantMessageReceivedEventArgs e)
{
//Can't set dependencyproperties directly from sub-thread
_imText = e.TextBody;
//Mark bool so main while loop exits
messageReceived = true;
}
//Callback to
private void OnMaximumTimerFired(object state)
{
_maximumTimerElapsed = true;
}
#region InstanceDependency dictionary
private Dictionary<string, object> _instanceDependencyProperties;
[Browsable(false)]
public Dictionary<string, object> InstanceDependencyProperties
{
get { return _instanceDependencyProperties; }
}
#endregion
#region Maximum Prompt Timeout
[NonSerialized]
private static readonly InstanceDependencyProperty MaximumPromptProperty = InstanceDependencyProperty.Register("MaximumPrompt", typeof(TimeSpan), typeof(CaptureIMInput), new TimeSpan(0, 0, 30));
[TypeConverter(typeof(TimeSpanConverter))]
public TimeSpan MaximumPrompt
{
get
{
if (base.DesignMode)
return (TimeSpan)InstanceDependencyHelper.GetValue<CaptureIMInput>(this, MaximumPromptProperty);
else
return (TimeSpan)InstanceDependencyHelper.GetValue<CaptureIMInput>(this, this.WorkflowInstanceId, MaximumPromptProperty);
}
set
{
if (base.DesignMode)
InstanceDependencyHelper.SetValue<CaptureIMInput>(this, MaximumPromptProperty, value);
else
InstanceDependencyHelper.SetValue<CaptureIMInput>(this, this.WorkflowInstanceId, MaximumPromptProperty, value);
}
}
#endregion
#region MainPrompt
public static DependencyProperty MainPromptProperty =
DependencyProperty.Register("MainPrompt", typeof(string), typeof(CaptureIMInput));
[ValidationOption(ValidationOption.Required)]
public string MainPrompt
{
get
{
return (string)base.GetValue(MainPromptProperty);
}
set
{
base.SetValue(MainPromptProperty, value);
}
}
#endregion
#region Instant Message Text
public static InstanceDependencyProperty IMTextProperty =
InstanceDependencyProperty.Register("IMText",
typeof(string),
typeof(CaptureIMInput));
[Description("InstantMessaging Text from user")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string IMText
{
get
{
if (base.DesignMode) return ((string)InstanceDependencyHelper.GetValue<CaptureIMInput>(this, CaptureIMInput.IMTextProperty));
else return ((string)(InstanceDependencyHelper.GetValue<CaptureIMInput>(this, this.WorkflowInstanceId, CaptureIMInput.IMTextProperty)));
}
set
{
if (base.DesignMode) InstanceDependencyHelper.SetValue<CaptureIMInput>(this, CaptureIMInput.IMTextProperty, value);
else InstanceDependencyHelper.SetValue<CaptureIMInput>(this, this.WorkflowInstanceId, CaptureIMInput.IMTextProperty, value);
}
}
#endregion
}
}
May I ask for help with the following?
I am attempting to connect and control three pieces of household electronic equipment by computer through a GlobalCache GC-100 and iTach. As you will see in the following code, I created a class ("GlobalCacheAdapter") that can communicate and control the equipment, and created an instance of the class for each piece of equipment. Although each instance seems to work well with communicating and in controlling each piece of equipment, the *feedback returned from the equipment* seems only to be visible at the defining class level's - "ReaderThreadProc" procedure. Further processing of the feedback is required for each piece of equipment and I am uncertain as to how to forward this feedback at the equipment specific instance-level. I suspect that an instance-specific EventHandler will need to be implemented; however I am not aware as to how to implement this type of instance-specific EventHandler in order to complete processing and update the appropriate controls.
Any help wold be greatly appreciated.
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
// Create three new instances of GlobalCacheAdaptor and connect.
// GC-100 (Elan) 192.168.1.70 4998
// GC-100 (TuneSuite) 192.168.1.70 5000
// GC iTach (Lighting) 192.168.1.71 4999
private GlobalCacheAdaptor elanGlobalCacheAdaptor;
private GlobalCacheAdaptor tuneSuiteGlobalCacheAdaptor;
private GlobalCacheAdaptor lutronGlobalCacheAdaptor;
public Form1()
{
InitializeComponent();
elanGlobalCacheAdaptor = new GlobalCacheAdaptor();
elanGlobalCacheAdaptor.ConnectToDevice(IPAddress.Parse("192.168.1.70"), 4998);
tuneSuiteGlobalCacheAdaptor = new GlobalCacheAdaptor();
tuneSuiteGlobalCacheAdaptor.ConnectToDevice(IPAddress.Parse("192.168.1.70"), 5000);
lutronGlobalCacheAdaptor = new GlobalCacheAdaptor();
lutronGlobalCacheAdaptor.ConnectToDevice(IPAddress.Parse("192.168.1.71"), 4999);
elanTextBox.Text = elanGlobalCacheAdaptor._line;
tuneSuiteTextBox.Text = tuneSuiteGlobalCacheAdaptor._line;
lutronTextBox.Text = lutronGlobalCacheAdaptor._line;
}
private void btnZoneOnOff_Click(object sender, EventArgs e) { elanGlobalCacheAdaptor.SendMessage("sendir,4:3,1,40000,4,1,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,800" + Environment.NewLine); }
private void btnSourceInput1_Click(object sender, EventArgs e) { elanGlobalCacheAdaptor.SendMessage("sendir,4:3,1,40000,1,1,20,179,20,179,20,179,20,179,20,179,20,179,20,179,20,278,20,179,20,179,20,179,20,780" + Environment.NewLine); }
private void btnSystemOff_Click(object sender, EventArgs e) { elanGlobalCacheAdaptor.SendMessage("sendir,4:3,1,40000,1,1,20,184,20,184,20,184,20,184,20,184,20,286,20,286,20,286,20,184,20,184,20,184,20,820" + Environment.NewLine); }
private void btnLightOff_Click(object sender, EventArgs e) { lutronGlobalCacheAdaptor.SendMessage("sdl,14,0,0,S2\x0d"); }
private void btnLightOn_Click(object sender, EventArgs e) { lutronGlobalCacheAdaptor.SendMessage("sdl,14,100,0,S2\x0d"); }
private void btnChannel31_Click(object sender, EventArgs e) { tuneSuiteGlobalCacheAdaptor.SendMessage("\xB8\x4D\xB5\x33\x31\x00\x30\x21\xB8\x0D"); }
private void btnChannel30_Click(object sender, EventArgs e) { tuneSuiteGlobalCacheAdaptor.SendMessage("\xB8\x4D\xB5\x33\x30\x00\x30\x21\xB8\x0D"); }
}
}
public class GlobalCacheAdaptor
{
public Socket _multicastListener;
public string _preferredDeviceID;
public IPAddress _deviceAddress;
public Socket _deviceSocket;
public StreamWriter _deviceWriter;
public bool _isConnected;
public int _port;
public IPAddress _address;
public string _line;
public GlobalCacheAdaptor() { }
public static readonly GlobalCacheAdaptor Instance = new GlobalCacheAdaptor();
public bool IsListening { get { return _multicastListener != null; } }
public GlobalCacheAdaptor ConnectToDevice(IPAddress address, int port)
{
if (_deviceSocket != null) _deviceSocket.Close();
try
{
_port = port;
_address = address;
_deviceSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_deviceSocket.Connect(new IPEndPoint(address, port)); ;
_deviceAddress = address;
var stream = new NetworkStream(_deviceSocket);
var reader = new StreamReader(stream);
var writer = new StreamWriter(stream) { NewLine = "\r", AutoFlush = true };
_deviceWriter = writer;
writer.WriteLine("getdevices");
var readerThread = new Thread(ReaderThreadProc) { IsBackground = true };
readerThread.Start(reader);
_isConnected = true;
return Instance;
}
catch { DisconnectFromDevice(); MessageBox.Show("ConnectToDevice Error."); throw; }
}
public void SendMessage(string message)
{
try
{
var stream = new NetworkStream(_deviceSocket);
var reader = new StreamReader(stream);
var writer = new StreamWriter(stream) { NewLine = "\r", AutoFlush = true };
_deviceWriter = writer;
writer.WriteLine(message);
var readerThread = new Thread(ReaderThreadProc) { IsBackground = true };
readerThread.Start(reader);
}
catch { MessageBox.Show("SendMessage() Error."); }
}
public void DisconnectFromDevice()
{
if (_deviceSocket != null)
{
try { _deviceSocket.Close(); _isConnected = false; }
catch { MessageBox.Show("DisconnectFromDevice Error."); }
_deviceSocket = null;
}
_deviceWriter = null;
_deviceAddress = null;
}
**private void ReaderThreadProc(object state)**
{
var reader = (StreamReader)state;
try
{
while (true)
{
var line = reader.ReadLine();
if (line == null) break;
_line = _line + line + Environment.NewLine;
}
**// Feedback from each piece of equipment is visible here.
// Need to create EventHandler to notify the TextBoxes to update with _line**
}
catch { MessageBox.Show("ReaderThreadProc Error."); }
}
}
From my understanding of the question, you want to do something like this?
You need to know when a GlobalCacheAdapter updates and which one updated in order to update textboxes on a form. My question to you is this - do you actually need to know which updated?
If you declare in your class an event handler like this:
public class GlobalCacheAdaptor
{
public event EventHandler<EventArgs> Updated;
protected virtual void OnUpdated()
{
var handler = Updated;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
private void Foo()
{
// When an update is received, raise Updated event
OnUpdated();
}
}
Then in your form subscribe to Updated for all three GlobalCacheHandler instances
public Form1()
{
elanGlobalCacheAdaptor.Updated += (s,e) =>
{
elanTextBox.Text = elanGlobalCacheAdaptor._line;
}
tuneSuiteGlobalCacheAdaptor.Updated += (s,e) =>
{
tuneSuiteTextBox.Text = tuneSuiteGlobalCacheAdaptor._line;
}
lutronGlobalCacheAdaptor.Updated += (s,e) =>
{
lutronTextBox.Text = lutronGlobalCacheAdaptor._line;
}
}
You should be able to update the correct text box when the appropriate cache handler raises the Updated event.
Finally you may need to handle cross-thread interactions. if so, see this article on MSDN, particularly the part "Thread-Safe Calls to a Windows Forms Control"