''' ''' User control responsible viewing, managing, and live editing the details of the movie collection. ''' ''' ''' Movies are added programatically by the SearchOnline control or are added manually after pressing the ''' Add button. Movies can be live edited by selecting a value in the grid. They can be deleted by selecting and pressing ''' Delete button. Press the View Online button to visit the Amazon.com Web site. Press Refresh button ''' to refresh data fields with live information from the Amazon.com Web service. ''' Movies are read from and written to MovieDatabase.mdf. It is recommended that movie information is ''' refreshed regularly. ''' Public Class ListDetails 'Represents the in memory representation of the movie collection. Type is defined in DVDCollectionDataSet.xsd file. 'This variable is defined again locally as WithEvents to make it easier to handle events in the code editor. Dim WithEvents dvdsDataTable As $safeprojectname$.DVDCollectionDataSet.DVDsDataTable Dim WithEvents hostingForm As Form 'Control object responsible for rating movie titles. 'Workaround: project cannot dynamically build this custom control type ' after using New Project wizard; the control instance is created and sited at runtime instead of ' adding to design surface. Friend WithEvents RatingPickerControl1 As RatingPickerControl 'Gets turned on, while database updates are occuring. Dim IsUpdating As Boolean = False ''' ''' Initializes this control and loads data. ''' ''' ''' All movie titles in the collection are loaded into the in-memory datatable; ''' The control monitors for changes to the datatable and auto saves changes made to each field. ''' Private Sub ListDetails_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'dynamically create rating picker control and site on the form InitRatingPickerControl() 'reference DVDs datatable on the design surface Me.dvdsDataTable = Me.DVDCollectionDataSet.DVDs 'load data from database If Me.LoadData() = 0 Then ' If no rows were available, create a new row so users can start entering a new dvd Me.DVDsBindingSource.AddNew() End If Me.TitleTextBox.Select() End Sub Private Sub dt_rowChanged(ByVal sender As Object, ByVal e As Data.DataRowChangeEventArgs) Handles dvdsDataTable.RowChanged If Me.IsUpdating Then Return End If Dim dvdDataRow As DVDCollectionDataSet.DVDsRow = CType(e.Row, DVDCollectionDataSet.DVDsRow) If dvdDataRow IsNot Nothing Then Me.SaveData() End If End Sub ''' ''' Creates a new movie in the collection when Add button is clicked. ''' ''' It is preferable to call AddNew from the dataconnector to keep data binding between the control and datatable in sync. Private Sub AddTitleButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddTitleButton.Click Me.DVDsBindingSource.AddNew() End Sub ''' Deletes the currently selected movie. Private Sub RemoveButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RemoveButton.Click Me.DeleteCurrent() End Sub ''' Applies the user-specified filter when clicked. Private Sub FilterButton_Clicked(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles FilterButton.Click Me.ApplyTextboxFilter() End Sub ''' Applies the user-specified filter when filter string is entered. Private Sub FilterTextBox_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles FilterTextBox.KeyUp If e.KeyCode = Keys.Enter Then Me.ApplyTextboxFilter() End If End Sub ''' Resets DataConnector to be unfiltered when button is clicked. Private Sub ShowAllButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ShowAllImage.Click, ShowAllButton.Click Me.DVDsBindingSource.Filter = "" End Sub ''' ''' Refreshes the current movie selection with data from the Amazon.com Web service after prompting the user. ''' ''' ''' Uses UPC value to fetch the movie title from the Web service, and merges/overwrites the ''' existing data. Comments and MyRating fields are preserved as a special case. ''' Private Sub RefreshOnlineButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RefreshOnlineButton.Click 'prompt the user to refresh and store the result Dim yesNoResult As MsgBoxResult = MsgBox("This feature will potentially overwrite your changes. Do you want to proceed? ", MsgBoxStyle.YesNo, "Refresh data from online Web service?") 'if yes, then begin refresh process If yesNoResult = MsgBoxResult.Yes Then 'object used to call Amazon.com Web service Dim amazonService As New SimpleAmazonWS 'objects used to store search result Dim refreshedDVD As DVD Dim refreshedDVDRow As $safeprojectname$.DVDCollectionDataSet.DVDsRow Try 'boundary check: make sure movie datatable is not empty If Me.DVDsBindingSource.Count > 0 Then 'gets the current movie selection and converts to a typed movie row object Dim rowView As DataRowView = CType(Me.DVDsBindingSource.Current, DataRowView) Dim dvdRow As DVDCollectionDataSet.DVDsRow = CType(rowView.Row, $safeprojectname$.DVDCollectionDataSet.DVDsRow) ' check to see if UPC value is null If (Not dvdRow.IsUPCNull) AndAlso dvdRow.UPC <> "" Then 'variables to store and preserve custom comment and rating values Dim currentComments As String = dvdRow.Comments Dim currentRating As Integer = dvdRow.MyRating 'get updated DVD object from Web service refreshedDVD = amazonService.RefreshDVDByUPC(dvdRow.UPC) 'update cached image Me.BoxArtPictureBox.Load(refreshedDVD.ImageUrl) refreshedDVD.ImageCache = Me.BoxArtPictureBox.Image 'convert DVD to dvdRow refreshedDVDRow = Me.DVDCollectionDataSet.DVDs.DVDsRowFromDVDObject(refreshedDVD) 'set the same ID as original row so row look up in the in-memory datatable succeeds refreshedDVDRow.ID = dvdRow.ID 'restore/merge back the custom comment and rating values refreshedDVDRow.Comments = currentComments refreshedDVDRow.MyRating = currentRating 'merge dvdRow with matching row Me.DVDCollectionDataSet.DVDs.LoadDataRow(refreshedDVDRow.ItemArray, LoadOption.Upsert) End If End If Catch ex As Exception MsgBox(String.Format("There was a problem refreshing the data from the online Web service: {0}", ex.Message)) My.Application.Log.WriteException(ex) End Try End If End Sub ''' ''' Navigates the to Amazon.com Web page for the current movie selection in an external browser after prompting the user. ''' ''' The user should see the hyperlink before starting the browser process and navigating to the URL. Private Sub ViewOnlineButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ViewOnlineButton.Click 'boundary check: make sure movie datatable is not empty If Me.DVDsBindingSource.Count > 0 Then 'gets the current movie selection and converts to a typed movie row object Dim rowView As DataRowView = CType(Me.DVDsBindingSource.Current, DataRowView) Dim dvdRow As DVDCollectionDataSet.DVDsRow = CType(rowView.Row, $safeprojectname$.DVDCollectionDataSet.DVDsRow) 'variable to store the Web page URL value Dim webLink As String = "" 'check for null before accessing WebPageLink property If Not dvdRow.IsWebPageLinkNull Then webLink = dvdRow.WebPageLink 'prompts to see if end user trusts URL and stores the prompt result value Dim msgText As String = String.Format("About to view this URL in an external browser: '{0}'. Is it safe to proceed?", webLink) Dim yesNoResult As MsgBoxResult = MsgBox(msgText, MsgBoxStyle.YesNo, "OK to browse?") 'start the URL path if the user approves the prompt If (yesNoResult = MsgBoxResult.Yes) AndAlso (webLink <> "") Then Process.Start(webLink) End If End If End Sub ''' ''' Prompts user for file to import when Clicked. ''' Private Sub ImportButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ImportButton.Click Me.OpenFileDialog1.ShowDialog() End Sub ''' ''' Imports image provided by user when user clicks OK to open file prompt. ''' Private Sub OpenFileDialog1_FileOk(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles OpenFileDialog1.FileOk Me.ImportImage(Me.OpenFileDialog1.FileName) End Sub ''' ''' Loads movie collection data. ''' ''' Positive integer for number of rows loaded; 0 if no rows are loaded. ''' Loads movie collection data into the in-memory datatable Friend Function LoadData() As Integer Dim rowsLoaded As Integer = 0 'Try to fill the datatable with the query of all movies. 'Note: If the database contains a large number of movies you'll likely want to add a query to the 'TableAdapter and only fill a subset of the movies in the database into memory. Try Me.IsUpdating = True rowsLoaded = Me.DVDsTableAdapter.Fill(Me.DVDCollectionDataSet.DVDs) Catch ex As Exception MsgBox(String.Format("There was a problem loading data: {0}", ex.Message)) My.Application.Log.WriteException(ex) Finally Me.IsUpdating = False End Try Return rowsLoaded End Function ''' ''' Saves changes made to movie collection data. ''' ''' Positive integer for number of rows updated in database; 0 if no rows are updated. ''' Saves the changes from in-memory datatable and bound UI. Friend Function SaveData() As Integer If IsUpdating Then Return 0 End If Dim rowsSaved As Integer = 0 'try to get changes and save to database Try 'only push update to database if changes are detected If Me.DVDCollectionDataSet.HasChanges Then IsUpdating = True rowsSaved = Me.DVDsTableAdapter.Update(Me.DVDCollectionDataSet.DVDs) End If Catch ex As Exception MsgBox(String.Format("There was a problem saving data: {0}", ex.Message)) My.Application.Log.WriteException(ex) Finally IsUpdating = False End Try Return rowsSaved End Function ''' ''' Applies filter over the in-memory movie records using the user-specified input in the text box. ''' ''' DataConnector object's Filter property is applied to all controls bound to the DataConnector. Private Sub ApplyTextboxFilter() Try 'sets filter string WHERE clause in the form "Where COLUMNNAME like '@FilterText'" Me.DVDsBindingSource.Filter = _ String.Format("{0} like '%{1}%'", _ Me.DVDCollectionDataSet.DVDs.TitleColumn.ColumnName, _ Me.FilterTextBox.Text) Catch End Try End Sub ''' Deletes the currently selected movie after prompting the user. Friend Sub DeleteCurrent() 'check for boundaries before performing delete: datatable is empty, or there is no selection If (Me.DVDsBindingSource.Count > 0) AndAlso (Me.DVDsBindingSource.Current IsNot Nothing) Then 'convert generic Current object returned by DataConnector to the typed movie row object Dim rowView As DataRowView = CType(Me.DVDsBindingSource.Current, DataRowView) Dim dvdRow As DVDCollectionDataSet.DVDsRow = CType(rowView.Row, $safeprojectname$.DVDCollectionDataSet.DVDsRow) 'string representing the friendly name of the current movie to be deleted Dim title As String = "[No Title]" 'use movie title property in the typed row object if it contains valid data If (Not dvdRow.IsTitleNull) AndAlso (dvdRow.Title IsNot Nothing) Then title = dvdRow.Title 'text displayed in a prompt to the user before deleting Dim msgText As String = String.Format("Are you sure you want to permanently delete {0} from your collection? ", title) 'display Yes/No prompt to the user and store the result Dim result As MsgBoxResult = MsgBox(msgText, MsgBoxStyle.YesNo, "OK to delete?") 'remove the current movie if the user accepts the prompt If result = MsgBoxResult.Yes Then Me.DVDsBindingSource.RemoveCurrent() End If ' Make sure we always have a row available If DVDsBindingSource.Count = 0 Then Me.DVDsBindingSource.AddNew() End If End If End Sub ''' ''' Initializes the rating picker control used on this user control. ''' ''' ''' Called by ListDetails.Load event. This special initialization code is not required if the ''' RatingPickerControl is built and referenced in a separate control library. ''' Private Sub InitRatingPickerControl() 'create rating picker control object and site it on the parent user control Me.RatingPickerControl1 = New RatingPickerControl Me.DVDDetailsPanel.Controls.Add(Me.RatingPickerControl1) 'set default properties and data binding CType(Me.RatingPickerControl1, System.ComponentModel.ISupportInitialize).BeginInit() Me.RatingPickerControl1.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) Me.RatingPickerControl1.BackColor = System.Drawing.Color.Transparent Me.RatingPickerControl1.CurrentRating = -1 Me.RatingPickerControl1.DataBindings.Add("CurrentRating", Me.DVDsBindingSource, "MyRating", True, DataSourceUpdateMode.OnPropertyChanged) Me.RatingPickerControl1.Location = New System.Drawing.Point(128, 388) Me.RatingPickerControl1.Name = "RatingPickerControl1" Me.RatingPickerControl1.Size = New System.Drawing.Size(80, 16) Me.RatingPickerControl1.TabIndex = 7 CType(Me.RatingPickerControl1, System.ComponentModel.ISupportInitialize).EndInit() End Sub ''' ''' Imports image value into datatable from file provided by user. ''' ''' Private Sub ImportImage(ByVal filename As String) Try 'check for boundaries before performing delete: datatable is empty, or there is no selection If Me.DVDsBindingSource.Current IsNot Nothing Then 'convert generic Current object returned by DataConnector to the typed movie row object Dim rowView As DataRowView = CType(Me.DVDsBindingSource.Current, DataRowView) Dim dvdRow As DVDCollectionDataSet.DVDsRow = CType(rowView.Row, $safeprojectname$.DVDCollectionDataSet.DVDsRow) 'open file as Readonly from file system, copy bytes, and assign to the image property of the current row dvdRow.ImageBinary = My.Computer.FileSystem.ReadAllBytes(filename) Me.DVDsBindingSource.ResetCurrentItem() End If Catch ex As Exception MsgBox(String.Format("There was a problem loading the image: {0}", ex.Message)) My.Application.Log.WriteException(ex) End Try End Sub Private Sub hostingForm_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Try 'call EndEdit to capture all changes made in the UI Me.DVDsBindingSource.EndEdit() Catch ex As Exception MsgBox(String.Format("There was a problem saving data: {0}", ex.Message)) My.Application.Log.WriteException(ex) End Try ' when the parent form is closing, be sure to save the data on this control Me.SaveData() End Sub Private Sub ListDetails_ParentChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.ParentChanged ' If the parent form for this user control ever changes we need to reset the form.Closed event handler for the new parent form If hostingForm IsNot Nothing Then RemoveHandler hostingForm.FormClosed, AddressOf hostingForm_FormClosed End If Me.hostingForm = Me.ParentForm AddHandler hostingForm.FormClosed, AddressOf hostingForm_FormClosed End Sub Private Sub TitleTextBox_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TitleTextBox.Click If Me.TitleTextBox.Text = "[New row - select to enter details]" Then Me.TitleTextBox.SelectAll() End If End Sub End Class