I am very new to SQL Dependencies and found this is a great way to handle data updating within my application. Previously I was constantly querying my Database every minute or so to check for changes, whereas now I receive update notifications on change events as they occur.
When my application first launches, it starts the SQL Dependency to the database with: SqlDependency.Start(ConnectionString) and in turn Stops it once I exit.
I then setup about 3 or 4 dependency queries to receive updates for different data within my application - all works great and exactly how I need.
However, my issue is this:
I have a second form of which I call multiple instances of. This form also has about 3 different dependencies attached to update different data again. However, when I close the instance of the form, I am finding that the dependency continues to run and thus throws an error in my application due to the form now being closed.
My question is: Is there a way I can stop the individual SQL Dependencies once I close the form? The dependencies on the Main form should continue to run, but every time I open and close an instance of the second form, I need to stop and start those queries from running.
Is this possible?
I can provide sample code snippets if required.
Any help appreciated. Thankyou
There is a Stop method in the SqlDependency class that you can invoke when you are done listening. Is there some issue with this?
ADDED
According to the docs, "Stops a listener for a connection specified in a previous Start call."
So, thhough I have not ever done exactly this, it should work if you are using a different connections in the main and child forms.
Okay, I ended up resolving this issue myself after a little bit of thought and researching.
Previously, I was declaring the SQLDependency within the same Sub Routine as the Handler like so:
Private Sub RefreshRegisterData()
...
Dim Register_dep As SqlDependency
Register_dep = New SqlDependency(cmd)
AddHandler Register_dep.OnChange, AddressOf Registers_OnChange
...
End Sub
However, to resolve my issue I basically moved the scope of the SQLDependency outside of the Sub Routine and declared it globally within the Class:
Public Class frmStorePage
Private Register_dep As SqlDependency
...
Private Sub RefreshRegisterData()
...
Register_dep = New SqlDependency(cmd)
AddHandler Register_dep.OnChange, AddressOf Registers_OnChange
...
End Sub
End Class
Then, when exiting my form, I simply implemented a RemoveHandler call to stop the message queue and destroy the existing handler:
Private Sub frmStorePage_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
RemoveHandler Register_dep.OnChange, AddressOf Registers_OnChange
...
End Sub
Now, not sure if this is the preferred method of solving this issue, however, I am yet to witness any implications by this code and it solves my problem.
Related
I have the following code:
Public Sub ExecuteMyCommand
ShowProgressBar=True
CallLongRunningProcess
ShowProgressBar=False
End Sub
To get the progressbar in the UI to actually show before the long running process starts this code has to be rewritten to:
Public Async Sub ExecuteMyCommand
ShowProgressBar=True
Await Task.Run(Sub() CallLongRunningProcess)
ShowProgressBar=False
End Sub
Now the problem:
In some methods the long running process involves creating WPF UserControls. These must be created on a STA thread. I have found how to do this, but then I get an InvalidOperationException because the user control is owned by non UI thread. So, I am looking for a way to update the ShowProgressBar property before calling the long running process on the UI thread (yeah, ugly, I know).
Did you try Dispatcher.Invoke? It keeps the tasks on the UI thread.
You'd have to move the ShowProgressBar=False into the delegate, of course.
Public Sub ExecuteMyCommand
ShowProgressBar=True
Me.Dispatcher.Invoke(DispatcherPriority.Normal, New LongRunningProcessDelegate())
End Sub
I'd also separate UI modifying logic from the computing task, i.e. the task should call back into the UI thread when its done, and modification of UI elements would be left to the callback.
I have read countless pages on how this can be achieved but none seem to be working for me.. I wonder if it is because I am using WPF??
I have an image control on my WPF page that holds an animated gif. Its initial Visibility property is set to hidden - the idea being it will become visible when the user logs in and then disappears once login has been achieved.
So, my first thought was to make the image visible on button click - carry out the grunt work then hide it again. However the image never gets displayed until after all the processing has completed - rendering the idea a useless one.
So, after a bit of digging it seems people have achieved this by processing a new thread and using the Background Worker object. I have tried this but continually get the error:
The calling thread cannot access this object because a different
thread owns it.
My code is as follows:
Global Variable for the thread object:
Friend g_thLoading As Thread
On button click for login on I have:
Private Sub btnLoginOk_Click(sender As Object, e As RoutedEventArgs) Handles btnLoginOk.Click
g_thLoading = New Thread(AddressOf LoadingImage)
g_thLoading.IsBackground = True
g_thLoading.Start()
Try
... Heavy Processing that takes a while ...
Catch liEX As UnauthorizedAccessException
txbResults.Text = liEX.Message()
Catch ex As Exception
MsgBox(ex.Message)
End Try
g_thLoading.Abort()
End Sub
Then the method for making the image visible:
Public Sub LoadingImage()
imgLoading.Visibility = Visibility.Visible
End Sub
I have read some posts about the error message stating to Freeze the object (cannot see how this works) and also look at using a Dispatcher - this is a little lost on me though as every example I have tried does not work.
We are trying to setup a SysTray application which can be activated from elsewhere. To be more specific the activation will come from a third party app which we cannot modify but allows us to activate our own app via its path (plus a parameter/argument).
When it gets activated we want to put up a BalloonText, there are to be no forms involved.
Therefore we have two problems to solve:
Make our SysTray application single instance (since it's no good generating multiple instances).
Allow this other app to activate our application with arguments
Lots of help out there to help learners create simple SysTray applications (and indeed we've done it ourselves as part of a solution to an unconnected project).
However we've never tried to make it single instance before.
Lots of help out there to help learners create single instance Winforms applications (again we've done this as part of other projects) but always simple applications with conventional forms (not SysTray). We use the VisualBasic WindowsFormsApplicationBase method.
Can't seem to combine these two approaches into a single solution.
Update:
Hans answer below nails it (and especially his comment):
This is already taken care of with a NotifyIcon, drop it on the form.
And the "Make single instance application" checkbox. And the
StartupNextInstance event. You'll need to stop assuming there's
anything special about this
As far as your first question about checking for other instances this seems to work. I used the CodeProject example as a baseline. In your Sub Main routine you can check for other instances by using the GetProcessesByName Method of the Process class. Something like this:
Public Sub Main()
'Turn visual styles back on
Application.EnableVisualStyles()
'Run the application using AppContext
Dim p() As Process
p = Process.GetProcessesByName("TrayApp") 'Your application name here
If UBound(p) >= 0 Then
End
End If
Application.Run(New AppContext)
End Sub
For the second question if your SysTray application is already running you might want to give this article on .Net Interprocess Communication a try. Otherwise parse the CommandLine arguments in yourSub Main as it is created.
From above article:
The XDMessaging library provides an easy-to-use, zero-configuration solution to same-box cross-AppDomain communications. It provides a simple API for sending and receiving targeted string messages across application boundaries. The library allows the use of user-defined pseudo 'channels' through which messages may be sent and received. Any application can send a message to any channel, but it must register as a listener with the channel in order to receive. In this way, developers can quickly and programmatically devise how best their applications can communicate with each other and work in harmony.
Everything becomes trivial when you actually do use a form. It is simple to put your app together with the designer, simple to get your app to terminate, simple to avoid a ghost icon in the tray, simple to create a context menu, simple to add popups if you ever need them.
The only un-simple thing is getting the form to not display. Paste this code in the form's class:
Protected Overrides Sub SetVisibleCore(ByVal value As Boolean)
If Not Me.IsHandleCreated Then
Me.CreateHandle()
value = False
End If
MyBase.SetVisibleCore(value)
End Sub
The "Exit" command in the context menu is now simply:
Private Sub ExitToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExitToolStripMenuItem.Click
Me.Close()
End Sub
I have an application that interacts with third party COM objects. A method of the COM object that I call will sometimes stop responding. I created a Backgroundworker thread to call the function and I am trying to monitor it from my main thread to kill it if it hangs. I have additional code (not supplied) that tracks the processing time using system.timer from the main thread and I raise an event if it exceeds my threshold (this part is fine). This is when I want to kill the thread and stop code execution. The problem is.. if I use the cancelasync method it will just pend since the code execution is stuck on the function call.
The particular function call in the code snippet that hangs is "objCOM.SendDataToServer()". It typically takes 1-3 seconds to return, but if it gets no response it will just hang indefinitely and won't return at all (no errors just hangs).. there is no timeout... and since I don't have access to the source function I cannot supply one. I tried the .dispose() method of the thread, but apparently that doesn't kill it and neither does cancelasync. I just need help figuring out how to KILL this thread so I can reset the server connection and call the function again. Any help is MUCH appreciated!
Public Class COMobject
Private objCOM as new acs.manager
Public Sub CallComFunction()
Dim bw_com as New Backgroundworker
AddHandler bw_com.DoWork, AddressOf bw_com_dowork
AddHandler bw_com.RunWorkerCompleted, AddressOf bw_com_runworkercompleted
AddHandler bw_com.ProgressChanged, AddressOf bw_com_progresschanged
bw_com.WorkerReportsProgress = True
bw_com.RunWorkerAsync()
End Sub
Private Sub bw_com_dowork(byval sender as object,byval e as doworkeventargs)
'this is the long running function that will hang
call objCOM.SendDataToServer()
End sub
End Class
I am a little hesitant to suggest this - but you may want to consider using the Win32 API - Terminate thread.
It is a very dangerous API to use and may leave your application in a potentially dangerous/inconsistent state, but for the given scenario - this is the only way that I can think off.
If it is permissible to perform the work in a separate process - Hans Passant's suggestion is the better one. It is much much safer to terminate a process rather than a thread.
I have started messing around with the MVVP pattern, and I am having some problems with UI responsiveness versus data processing.
I have a program that tracks packages. Shipment and package entities are persisted in SQL database, and are displayed in a WPF view. Upon initial retrieval of the records, there is a noticeable pause before displaying the new shipments view, and I have not even implemented the code that counts shipments that are overdue/active yet (which will necessitate a tracking check via web service, and a lot of time).
I have built this with the Ocean framework, and all appears to be doing well, except when I first started my foray into multi-threading. It broke, and it appeared to break something in Ocean... Here is what I did:
Private QueryThread As New System.Threading.Thread(AddressOf GetShipments)
Public Sub New()
' Insert code required on object creation below this point.
Me.New(ViewManagerService.CreateInstance, ViewModelUIService.CreateInstance)
'Perform initial query of shipments
'QueryThread.Start()
GetShipments()
Console.WriteLine(Me.Shipments.Count)
End Sub
Public Sub New(ByVal objIViewManagerService As IViewManagerService, ByVal objIViewModelUIService As IViewModelUIService)
MyBase.New(objIViewModelUIService)
End Sub
Public Sub GetShipments()
Dim InitialResults = From shipment In db.Shipment.Include("Packages") _
Select shipment
Me.Shipments = New ShipmentsCollection(InitialResults, db)
End Sub
So I declared a new Thread, assigned it the GetShipments method and instanced it in the default constructor. Ocean freaks out at this, so there must be a better way of doing it.
I have not had the chance to figure out the usage of the SQL ORM thing in Ocean so I am using Entity Framework (perhaps one of these days i will look at NHibernate or something too).
I have looked at a number of articles and they all have examples of simple uses. Some have mentioned the Dispatcher, but none really go very far into how it is used.
The way I do it is, using a backgroundworker. Then I use MVVM Light to send a message to the main ui to update progress.