unity crashes when script runs - unity3d

in my simple usp server finder script when i select client it makes unity crash and i can't find why;
import System.Net.Sockets;
private var udp_server:UdpClient;
private var udp_client:UdpClient;
private var udp_port:int = 18000;
private var udp_broadcast_ip:IPAddress = IPAddress.Parse ("224.0.0.224");
private var udp_received_message:String;
private var udp_endpoint:IPEndPoint;
private var selected:boolean = false;
private var clientStarted:boolean = false;
function StartServer(){
udp_server = new UdpClient(udp_port, AddressFamily.InterNetwork);
udp_server.JoinMulticastGroup(udp_broadcast_ip);
udp_endpoint = new IPEndPoint(udp_broadcast_ip, udp_port);
InvokeRepeating("StartBroadcastUDP", 0.0,0.3);
}
function StartClient(){
udp_client = new UdpClient();
udp_endpoint = new IPEndPoint(IPAddress.Any, udp_port);
udp_client.Client.Bind(udp_endpoint);
udp_client.JoinMulticastGroup(udp_broadcast_ip);
/*
while(true){
yield;
var udp_received_message_byte:byte[] = udp_client.Receive(udp_endpoint);
udp_received_message = Encoding.Unicode.GetString(udp_received_message_byte);
print("Received Message: " + udp_received_message);
}*/
clientStarted = true;
}
function StartBroadcastUDP(){
var udp_broadcast_message = Encoding.Unicode.GetBytes("GAME SERVER");
if(udp_broadcast_message != ""){
udp_server.Send(udp_broadcast_message, udp_broadcast_message.Length);
}
}
function OnGUI(){
if(!selected){
if(GUI.Button(Rect(0, 0, 100, 100), "Server")){
StartServer();
selected = true;
}else if(GUI.Button(Rect(100, 0, 100, 100), "Client")){
StartClient();
selected = true;
}
}
}
function Update(){
/*
if(clientStarted){
var udp_received_message_byte:byte[] = udp_client.Receive(udp_endpoint);
udp_received_message = Encoding.Unicode.GetString(udp_received_message_byte);
print("Received Message: " + udp_received_message);
}*/
}
in both of the commented parts i tried doing this, in the first i used while to keep it in the same function but it crashed so i mmoved it into the update function but it still crashes. help?

The while(true)in StartClient() will indeed make the editor / app to be frozen, because StartClient() is not called as a Coroutine, so yield does not return to the Unity engine, and your program is stuck forever in the while.
There is another thing thus. It looks like udp-client.Receive is a synchronous call, meaning it's blocking the code waiting for a packet. The game will indeed freeze unless you have like 60 packets per seconds.

Related

My Unity (ZXing/XR) QRCode reader isn't presenting the decoded info. What am I doing wrong?

This is the code I am using for QR Scan. It uses XR for Camera input and ZXing to decode the QR Code. I have been at this for 3 days and still have no clue what I am doing wrong. I do not know whether it is that code isn't able to decode the QR, or it can but isn't able to print it out on Output text. Any help would be greatly appreciated. Thank you! :)
These are the libraries I am using :
using System.Collections;
using UnityEngine;
using UnityEngine.XR.ARSubsystems;
using UnityEngine.XR.ARFoundation;
using ZXing;
using TMPro;
This is the code :
IBarcodeReader _reader;
ARCameraManager _arCam;
AudioSource _audioSrc;
ARRaycastManager _arRay;
private Texture2D _arTexture;
private TextMeshPro _outputText;
private void Awake()
{
_arCam = FindObjectOfType<ARCameraManager>();
_audioSrc = FindObjectOfType<AudioSource>();
_arRay = FindObjectOfType<ARRaycastManager>();
_reader = new BarcodeReader();
_arCam.frameReceived += OnCameraFrameReceived; //When camera receives frame.
}
//Fires off when Frame is received.
void OnCameraFrameReceived(ARCameraFrameEventArgs eventArgs)
{
if ((Time.frameCount % 15) == 0)
{
XRCpuImage _image;
if(_arCam.TryAcquireLatestCpuImage(out _image))
{
StartCoroutine(ProcessQRCode(_image));
_image.Dispose();
}
}
}
//Processes the QR Code in the _image.
IEnumerator ProcessQRCode(XRCpuImage _image)
{
var request = _image.ConvertAsync(new XRCpuImage.ConversionParams { inputRect = new RectInt(0, 0, _image.width, _image.height),
outputDimensions = new Vector2Int(_image.width / 2, _image.height / 2),
outputFormat = TextureFormat.RGB24
});
while (!request.status.IsDone())
yield return null;
if (request.status != XRCpuImage.AsyncConversionStatus.Ready)
{
Debug.LogErrorFormat("Request failed with status {0}", request.status);
request.Dispose();
yield break;
}
var rawData = request.GetData<byte>();
if(_arTexture == null)
{
_arTexture = new Texture2D(
request.conversionParams.outputDimensions.x,
request.conversionParams.outputDimensions.y,
request.conversionParams.outputFormat,
false
);
}
_arTexture.LoadRawTextureData(rawData);
_arTexture.Apply();
byte[] barcodeBitmap = _arTexture.GetRawTextureData();
LuminanceSource source = new RGBLuminanceSource(barcodeBitmap, _arTexture.width, _arTexture.height);
var result = _reader.Decode(source);
if(result != null)
{
var QRContents = result.Text;
_outputText.text = QRContents;
_audioSrc.Play();
}
}

How can I reconnect a Photon Bolt client after it disconnects?

I'm trying to make a Photon Bolt game that connects two devices. The problem is that the Client tends to get disconnected a lot, an it doesn't reconnect automatically. I've tried using methods like ReconnectAndRejoin, but it seems like it only works in PUN. Right now I'm using this custom solution, without success:
[BoltGlobalBehaviour(BoltNetworkModes.Client)]
public class InitialiseGameClient : Photon.Bolt.GlobalEventListener
{
private bool disconnected;
public void Update(){
if(disconnected){
Reconnect();
}
}
public override void Disconnected(BoltConnection connection)
{
disconnected = true;
}
public void Reconnect(){
BoltLauncher.StartClient();
PlayerPrefs.DeleteAll();
if (BoltNetwork.IsRunning && BoltNetwork.IsClient)
{
foreach (var session in BoltNetwork.SessionList)
{
UdpSession udpSession = session.Value as UdpSession;
if (udpSession.Source != UdpSessionSource.Photon)
continue;
PhotonSession photonSession = udpSession as PhotonSession;
string sessionDescription = String.Format("{0} / {1} ({2})",
photonSession.Source, photonSession.HostName, photonSession.Id);
RoomProtocolToken token = photonSession.GetProtocolToken() as RoomProtocolToken;
if (token != null)
{
sessionDescription += String.Format(" :: {0}", token.ArbitraryData);
}
else
{
object value_t = -1;
object value_m = -1;
if (photonSession.Properties.ContainsKey("t"))
{
value_t = photonSession.Properties["t"];
}
if (photonSession.Properties.ContainsKey("m"))
{
value_m = photonSession.Properties["m"];
}
sessionDescription += String.Format(" :: {0}/{1}", value_t, value_m);
}
ServerConnectToken connectToken = new ServerConnectToken
{
data = "ConnectTokenData"
};
Debug.Log((int)photonSession.Properties["t"]);
var propertyID = PlayerPrefs.GetInt("PropertyID", 2);;
if((int)photonSession.Properties["t"] == propertyID){
BoltMatchmaking.JoinSession(photonSession, connectToken);
disconnected = false;
}
}
}
}
}
With this method I'm trying to use the same code used to connect the the client for the first time in the reconnect function, and keep trying until the client manages to connect. However it seems that the code never executes, even if the disconnect function gets triggered (the reconnect doesn't). Is there any Bolt integrated function that helps with reconnecting? Thanks in advance.
You need to shutdown bolt, then try reconnecting. Even if you don't get the below exception, it's just an example and you should shutdown and do BoltLauncher.StartClient() etc.
BoltException: Bolt is already running, you must call BoltLauncher.Shutdown() before starting a new instance of Bolt.

Livestream playback on Hololens2

I have encountered the following problem
My task is as follows, I need to play streaming video (raw h264 video over UDP protocol) on a 3d object. At the moment I'm using FFmpegInteropX to set a MediaSource to a Windows object.Media.Playback.MediaPlayer.
Media Player works in frame server mode, then I subscribe to the videoFrameAvailable event and transmit the resulting frame to Unity
The problem is that the performance on Hololens2 (UWP) is quite low, I can't get enough smoothness and low latency if I use texture sizes greater than 720x720. At the same time, if I run the application on a PC, I can play everything up to 4096x4096 smoothly and without delay.
Perhaps someone has some ideas on how to improve performance on Hololens2?
private SoftwareBitmap frameServerDest = new SoftwareBitmap(BitmapPixelFormat.Rgba8, 1024,1024,BitmapAlphaMode.Premultiplied );
private UnityEngine.Texture2D tex = new UnityEngine.Texture2D(frameServerDest.PixelWidth, frameServerDest.PixelHeight, UnityEngine.TextureFormat.RGBA32, false);
private async void InitializeMediaPlayer(){
FFmpegInteropLogging.SetDefaultLogProvider();
FFmpegInteropConfig configuration = new FFmpegInteropConfig()
{
MaxVideoThreads = 8,
SkipErrors = uint.MaxValue,
DefaultBufferTime = TimeSpan.Zero,
FastSeek = true,
VideoDecoderMode = VideoDecoderMode.ForceFFmpegSoftwareDecoder,
};
configuration.FFmpegOptions.Add("tune", "zerolatency");
configuration.FFmpegOptions.Add("flags", "low_delay");
configuration.FFmpegOptions.Add("fflags", "discardcorrupt+shortest+sortdts+ignidx+nobuffer");
decoder = await FFmpegInteropMSS.CreateFromUriAsync("udp://127.0.0.1:9005",configuration)
var mediaStreamSource = decoder.GetMediaStreamSource();
mediaStreamSource.BufferTime = TimeSpan.FromSeconds(0);
Debug.WriteLine($"{decoder.CurrentVideoStream.CodecName} {decoder.CurrentVideoStream.DecoderEngine} {decoder.CurrentVideoStream.HardwareDecoderStatus} {decoder.CurrentVideoStream.PixelWidth} x {decoder.CurrentVideoStream.PixelHeight}");
var FrameServer = new Windows.Media.Playback.MediaPlayer() { IsVideoFrameServerEnabled = true };
FrameServer.Source = MediaSource.CreateFromMediaStreamSource(mediaStreamSource);
FrameServer.RealTimePlayback = true;
FrameServer.VideoFrameAvailable += MediaPlayer_VideoFrameAvailable;
FrameServer.Play();
}
//FrameAvailable:
private void MediaPlayer_VideoFrameAvailable(Windows.Media.Playback.MediaPlayer sender, object args)
{
CanvasDevice canvasDevice = CanvasDevice.GetSharedDevice();
using (CanvasBitmap canvasBitmap = CanvasBitmap.CreateFromSoftwareBitmap(canvasDevice, frameServerDest))
{
sender.CopyFrameToVideoSurface(canvasBitmap);
byte[] bytes = canvasBitmap.GetPixelBytes();
if (AppCallbacks.Instance.IsInitialized())
{
AppCallbacks.Instance.InvokeOnAppThread(() =>
{
tex.LoadRawTextureData(bytes);
tex.Apply();
Display.GetComponent<UnityEngine.UI.RawImage>().texture = tex;
}, false);
}
GC.Collect();
}
}
My FFmpeg output setting
ffmpeg -r 60 -f gdigrab -i desktop -f h264 -framerate 60 -vcodec libx264 -preset ultrafast -tune zerolatency -threads 8 -thread_type slice udp://127.0.0.1:9005
UPDATE:
Hello, I did some work.
What I've done:
I have established a direct connection via usb-s - etnernet
I begin to look towards using directx surface
I found the following way to get d3d11 device using by Unity
For this I had to use the library SharpDX, and similar thread https://forum.unity.com/threads/d3d11-texture2d-blitting-framerate.562552
But there are problems that I can't solve yet:
1 FFmpeg works only in the VideoDecoderMode = VideoDecoderMode.Automatic or VideoDecoderMode.ForceFFmpegSoftwareDecoder mode;
2 In the event handler (videoframe_available), there is still a very large load on the Garbage Collector, and apparently this causes performance problems. Moreover, the performance suffers only on Hololens.
In other VideoDecoderMode`s, the stream parameters are determined, but the videoframe_available event never fires. Latency is approx to zero, but perfomance still not very good
Perhaps there are ideas how to solve the problem with GarbageColletor?
private SoftwareBitmap frameServerDist = new SoftwareBitmap(BitmapPixelFormat.Rgba8, 780, 780,
BitmapAlphaMode.Premultiplied);
private FFmpegInteropMSS decoder;
private UnityEngine.GameObject Display;
private UnityEngine.Texture2D targetTexture;
private UnityEngine.GameObject MainCamera;
private SharpDX.Direct3D11.Device dstDevice;
private SharpDX.Direct3D11.DeviceContext dstContenxt;
private SharpDX.Direct3D11.Texture2D m_DstTexture;
private SharpDX.Direct3D11.Device srcDevice;
private SharpDX.Direct3D11.DeviceContext srcContext;
private static DataRectangle _rect;
private SharpDX.Direct3D11.Texture2DDescription Texture2DDescription = new SharpDX.Direct3D11.Texture2DDescription()
{
ArraySize = 1,
BindFlags = SharpDX.Direct3D11.BindFlags.ShaderResource,
Usage = SharpDX.Direct3D11.ResourceUsage.Immutable, //GPU Only
CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.None,
Format = SharpDX.DXGI.Format.R8G8B8A8_UNorm,
MipLevels = 1,
OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.None,
SampleDescription = new SharpDX.DXGI.SampleDescription()
{
Count = 1,
Quality = 0
}
};
//This event occurs when UnityEngine Initialized
private void AppCallbacks_Initialized()
{
srcDevice = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware);
srcContext = srcDevice.ImmediateContext;
UnityEngine.WSA.Application.InvokeOnAppThread(() =>
{
Display = UnityEngine.GameObject.Find("Display");
targetTexture = null;
//Create texture for get Device and Device context
UnityEngine.Texture2D deviceTexture = new UnityEngine.Texture2D(frameServerDist.PixelWidth, frameServerDist.PixelHeight, UnityEngine.TextureFormat.RGBA32, false);
IntPtr txPtr = deviceTexture.GetNativeTexturePtr();
SharpDX.Direct3D11.Texture2D dstTextureX = new SharpDX.Direct3D11.Texture2D(txPtr);
dstDevice = dstTextureX.Device;
dstContenxt = dstDevice.ImmediateContext;
//Create sharedResource
SharpDX.Direct3D11.Texture2DDescription sharedTextureDesc = dstTextureX.Description;
sharedTextureDesc.OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.Shared;
m_DstTexture = new SharpDX.Direct3D11.Texture2D(dstDevice, sharedTextureDesc);
SharpDX.Direct3D11.ShaderResourceViewDescription rvdesc = new SharpDX.Direct3D11.ShaderResourceViewDescription
{
Format = sharedTextureDesc.Format,
Dimension = SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D
};
rvdesc.Texture2D.MostDetailedMip = 0; rvdesc.Texture2D.MipLevels = 1;
SharpDX.Direct3D11.ShaderResourceView rvptr = new SharpDX.Direct3D11.ShaderResourceView(
dstDevice,
m_DstTexture, rvdesc);
targetTexture = UnityEngine.Texture2D.CreateExternalTexture(sharedTextureDesc.Width, sharedTextureDesc.Height, UnityEngine.TextureFormat.BGRA32, false, false, rvptr.NativePointer);
MainCamera = UnityEngine.GameObject.Find("Main Camera");
Display.GetComponent<UnityEngine.UI.RawImage>().texture = targetTexture;
InitializeMediaPlayer();
}, false);
private void MediaPlayer_VideoFrameAvailable(Windows.Media.Playback.MediaPlayer sender, object args)
{
canvasBitmap = CanvasBitmap.CreateFromSoftwareBitmap(canvasDevice, frameServerDist);
sender.CopyFrameToVideoSurface(canvasBitmap);
var sharedResourceDst = m_DstTexture.QueryInterface<SharpDX.DXGI.Resource>();
var sharedTexDst = srcDevice.OpenSharedResource<SharpDX.Direct3D11.Texture2D>(sharedResourceDst.SharedHandle);
using (var _stream = DataStream.Create(canvasBitmap.GetPixelBytes(), true, false))
{
_rect.DataPointer = _stream.DataPointer;
_rect.Pitch = Texture2DDescription.Width * 4;
var srcTexture = new SharpDX.Direct3D11.Texture2D(srcDevice, Texture2DDescription, _rect);
srcContext.CopyResource(srcTexture, sharedTexDst);
srcContext.Flush();
sharedResourceDst.Dispose();
sharedTexDst.Dispose();
srcTexture.Dispose();
}
}
The problem was copying from CPU to GPU, the SharpDX library allowed copying frames directly to Idirect3dsurface. I'm attaching the code, maybe it will be useful.
Direct3D11 helpers is available in the microsoft documentation
https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/screen-capture-video#helper-wrapper-classes
private UnityEngine.GameObject MainCamera;
private UnityEngine.Texture2D targetTexture;
private IDirect3DSurface surface;
private SharpDX.Direct3D11.Device dstDevice;
private void AppCallbacks_Initialized()
{
SharpDX.Direct3D11.Device srcDevice = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware);
UnityEngine.WSA.Application.InvokeOnAppThread(() =>
{
Display = UnityEngine.GameObject.Find("Display");
targetTexture = null;
//Create texture for get Device and Device context from Unity
UnityEngine.Texture2D deviceTexture = new UnityEngine.Texture2D(2048, 2048, UnityEngine.TextureFormat.RGBA32, false);
IntPtr txPtr = deviceTexture.GetNativeTexturePtr();
SharpDX.Direct3D11.Texture2D dstTexture = new SharpDX.Direct3D11.Texture2D(txPtr);
dstDevice = dstTexture.Device;
//Create sharedResource
SharpDX.Direct3D11.Texture2DDescription sharedTextureDesc = dstTexture.Description;
sharedTextureDesc.OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.Shared;
SharpDX.Direct3D11.Texture2D m_DstTexture = new SharpDX.Direct3D11.Texture2D(dstDevice, sharedTextureDesc);
SharpDX.Direct3D11.ShaderResourceViewDescription rvdesc = new SharpDX.Direct3D11.ShaderResourceViewDescription
{
Format = sharedTextureDesc.Format,
Dimension = SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D
};
rvdesc.Texture2D.MostDetailedMip = 0;
rvdesc.Texture2D.MipLevels = 1;
SharpDX.Direct3D11.ShaderResourceView rvptr = new SharpDX.Direct3D11.ShaderResourceView(
dstDevice,
m_DstTexture, rvdesc);
targetTexture = UnityEngine.Texture2D.CreateExternalTexture(sharedTextureDesc.Width, sharedTextureDesc.Height, UnityEngine.TextureFormat.BGRA32, false, false, rvptr.NativePointer);
MainCamera = UnityEngine.GameObject.Find("Main Camera");
Display.GetComponent<UnityEngine.UI.RawImage>().texture = targetTexture;
var sharedResourceDst = m_DstTexture.QueryInterface<SharpDX.DXGI.Resource>();
var sharedTexDst = srcDevice.OpenSharedResource<SharpDX.Direct3D11.Texture2D>(sharedResourceDst.SharedHandle);
surface = Direct3D11Helper.CreateDirect3DSurfaceFromSharpDXTexture(sharedTexDst);
sharedResourceDst.Dispose();
sharedTexDst.Dispose();
dstTexture.Dispose();
m_DstTexture.Dispose();
}, false);
InitializeMediaPlayer();
}
private void MediaPlayer_VideoFrameAvailable(Windows.Media.Playback.MediaPlayer sender, object args)
{
Debug.WriteLine("frameAvail");
sender.CopyFrameToVideoSurface(surface);
}

Xamarin Forms Sockets

I don't get it, my friend and I are developing an API and our WebSocket services works, but not the mobile side.. I tried with a couple of clients, on the web, our echo messaging and everything works.
The thing is, I mean, the things seem like the socket is mono-directional. I tried the example of https://github.com/rdavisau/sockets-for-pcl#a-tcp-client:
var address = "127.0.0.1";
var port = 11000;
var r = new Random();
var client = new TcpSocketClient();
await client.ConnectAsync(address, port);
// we're connected!
for (int i = 0; i<5; i++)
{
// write to the 'WriteStream' property of the socket client to send data
var nextByte = (byte) r.Next(0,254);
client.WriteStream.WriteByte(nextByte);
await client.WriteStream.FlushAsync();
// wait a little before sending the next bit of data
await Task.Delay(TimeSpan.FromMilliseconds(500));
}
await client.DisconnectAsync();
First, after I get connected with this :
public async void ConnectSocketToAPIAsync()
{
SocketClient = new TcpSocketClient();
await SocketClient.ConnectAsync("my.ws.service", 4242);
ActiveSocketExchange();
}
public async void ActiveSocketExchange()
{
var bytesRead = -1;
var buf = new byte[1];
while (bytesRead != 0)
{
bytesRead = await SocketClient.ReadStream.ReadAsync(buf, 0, 1);
if (bytesRead > 0)
MessagingCenter.Send((App)Current, SOCKET_Message, System.Text.Encoding.UTF8.GetString(buf, 0, bytesRead));
}
}
Everything's fine, my TcpClient is well initialized (even the web-link becomes the http's API addr)
From my page view, when I'm done writing my text, I'm pressing the done button of the keyboard and this code is called:
private void InitSocketPart()
{
MessagingCenter.Subscribe<App, string>((App)Application.Current, App.SOCKET_Message, (sender, text) =>
{
SocketResponseText = text;
});
}
private async void OnTextCompleted(object sender, EventArgs ea)
{
var bytes = Encoding.UTF8.GetBytes(TextToSend);
try {
if (App.SocketClient.WriteStream.CanRead)
Debug.WriteLine("canRead");
if (App.SocketClient.WriteStream.CanWrite)
Debug.WriteLine("canWrite");
App.SocketClient.WriteStream.Write(bytes, 0, TextToSend.Length);
App.SocketClient.WriteStream.Flush();
} catch (Exception e)
{
Debug.WriteLine(e);
}
}
So now CanWrite && CanRead are true, but nothing at all happens, even with the use of Async methods... Why so? I don't get it..
The use of messaging center is just to have only one point of incoming message. I'm using it for other things and it works perfectly :)
Thank for any help..

Unstable application uses SqlDependency. Several states and errors

I have a windows application using SqlDependency running at separated thread pool, this application represents a log monitor UI get the latest rows added in a specific table in the database and view it in a DataGridView. You can see the application source code from this LINK, or follow this script.
const string tableName = "OutgoingLog";
const string statusMessage = "{0} changes have occurred.";
int changeCount = 0;
private static DataSet dataToWatch = null;
private static SqlConnection connection = null;
private static SqlCommand command = null;
public frmMain()
{
InitializeComponent();
}
private bool CanRequestNotifications()
{
// In order to use the callback feature of the
// SqlDependency, the application must have
// the SqlClientPermission permission.
try
{
SqlClientPermission perm = new SqlClientPermission(PermissionState.Unrestricted);
perm.Demand();
return true;
}
catch
{
return false;
}
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
// This event will occur on a thread pool thread.
// Updating the UI from a worker thread is not permitted.
// The following code checks to see if it is safe to
// update the UI.
ISynchronizeInvoke i = (ISynchronizeInvoke)this;
// If InvokeRequired returns True, the code
// is executing on a worker thread.
if (i.InvokeRequired)
{
// Create a delegate to perform the thread switch.
OnChangeEventHandler tempDelegate = new OnChangeEventHandler(dependency_OnChange);
object[] args = { sender, e };
// Marshal the data from the worker thread
// to the UI thread.
i.BeginInvoke(tempDelegate, args);
return;
}
// Remove the handler, since it is only good
// for a single notification.
SqlDependency dependency = (SqlDependency)sender;
dependency.OnChange -= dependency_OnChange;
// At this point, the code is executing on the
// UI thread, so it is safe to update the UI.
++changeCount;
lblChanges.Text = String.Format(statusMessage, changeCount);
// Reload the dataset that is bound to the grid.
GetData();
}
AutoResetEvent running = new AutoResetEvent(true);
private void GetData()
{
// Start the retrieval of data on another thread to let the UI thread free
ThreadPool.QueueUserWorkItem(o =>
{
running.WaitOne();
// Empty the dataset so that there is only
// one batch of data displayed.
dataToWatch.Clear();
// Make sure the command object does not already have
// a notification object associated with it.
command.Notification = null;
// Create and bind the SqlDependency object
// to the command object.
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
adapter.Fill(dataToWatch, tableName);
try
{
running.Set();
}
finally
{
// Update the UI
dgv.Invoke(new Action(() =>
{
dgv.DataSource = dataToWatch;
dgv.DataMember = tableName;
//dgv.FirstDisplayedScrollingRowIndex = dgv.Rows.Count - 1;
}));
}
}
});
}
private void btnAction_Click(object sender, EventArgs e)
{
changeCount = 0;
lblChanges.Text = String.Format(statusMessage, changeCount);
// Remove any existing dependency connection, then create a new one.
SqlDependency.Stop("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True");
SqlDependency.Start("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True");
if (connection == null)
{
connection = new SqlConnection("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True");
}
if (command == null)
{
command = new SqlCommand("select * from OutgoingLog", connection);
//SqlParameter prm =
// new SqlParameter("#Quantity", SqlDbType.Int);
//prm.Direction = ParameterDirection.Input;
//prm.DbType = DbType.Int32;
//prm.Value = 100;
//command.Parameters.Add(prm);
}
if (dataToWatch == null)
{
dataToWatch = new DataSet();
}
GetData();
}
private void frmMain_Load(object sender, EventArgs e)
{
btnAction.Enabled = CanRequestNotifications();
}
private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
SqlDependency.Stop("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True");
}
The problem:
I have many situations of errors, (images in the first comment)
(No. 1):
I got this error dialog, and I don't know its reason.
(No. 2):
I got nothing in my grid view (No errors, and no data).
(No. 3):
I got only columns names and no rows, although the table has rows.
I need help please.
I may be wrong but a DataSet does not seem to have notification capability so the DataGridView may be surprised if you change it behind its back.
You could try to explicitly show your're changing the data source by first setting it to null:
dgv.DataSource = null;
dgv.DataSource = dataToWatch;
dgv.DataMember = tableName;
It's worth a try...