using System; using System.Data; using System.Drawing; using System.Diagnostics; using System.IO; using System.Windows.Forms; using $safeprojectname$.Controls; namespace $safeprojectname$ { /// /// 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 partial class ListDetails : UserControl { System.Windows.Forms.Form hostingForm; //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. internal RatingPickerControl ratingPickerControl; //Gets turned on, while database updates are occuring. bool isUpdating; /// /// 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 void ListDetails_Load(System.Object sender, System.EventArgs e) { //dynamically create rating picker control and site on the form InitRatingPickerControl(); //listen for data changes when adding, modifying, and deleting in UI this.dvdCollectionDataSet.DVDs.TableNewRow += new DataTableNewRowEventHandler(this.dvdCollectionDataSet.DVDs.dvdsDataTable_TableNewRow); this.dvdCollectionDataSet.DVDs.RowChanged += new DataRowChangeEventHandler(dt_RowChanged); //load data from database if (this.LoadData() == 0){ //if no rows were available, create a new row so users can start entering a new dvd this.dvdsDataConnector.AddNew(); } this.titleTextBox.Select(); } /// /// Detects any changes made to the datatable and saves changes to the database. /// private void dt_RowChanged(object sender, System.Data.DataRowChangeEventArgs e) { if (isUpdating){ return; } $safeprojectname$.DVDCollectionDataSet.DVDsRow dvdDataRow = ($safeprojectname$.DVDCollectionDataSet.DVDsRow) e.Row; if (dvdDataRow != null){ SaveData(); } } /// /// 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 void AddTitleButton_Click(System.Object sender, System.EventArgs e) { this.dvdsDataConnector.AddNew(); } /// /// Deletes the currently selected movie. /// private void RemoveButton_Click(System.Object sender, System.EventArgs e) { DeleteCurrent(); } /// /// Applies the user-specified filter when clicked. /// private void FilterButton_Clicked(System.Object sender, System.EventArgs e) { ApplyTextboxFilter(); } /// /// Applies the user-specified filter when filter string is entered. /// private void FilterTextBox_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { ApplyTextboxFilter(); } } /// /// Resets DataConnector to be unfiltered when button is clicked. /// private void ShowAllButton_Click(System.Object sender, System.EventArgs e) { this.dvdsDataConnector.Filter = ""; } /// /// 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 void RefreshOnlineButton_Click(System.Object sender, System.EventArgs e) { //prompt the user to refresh and store the result DialogResult dialogResult = MessageBox.Show("This feature will potentially overwrite your changes. Do you want to proceed? ", "Refresh data from online Web service?", MessageBoxButtons.YesNo); //if yes, then begin refresh process if (dialogResult == DialogResult.Yes) { //object used to call Amazon.com Web service SimpleAmazonWS amazonService = new SimpleAmazonWS(); //objects used to store search result DVD refreshedDVD; $safeprojectname$.DVDCollectionDataSet.DVDsRow refreshedDVDRow; try { //boundary check: make sure movie datatable is not empty if (this.dvdsDataConnector.Count > 0) { //gets the current movie selection and converts to a typed movie row object DataRowView rowView = (DataRowView)this.dvdsDataConnector.Current; $safeprojectname$.DVDCollectionDataSet.DVDsRow dvdRow = ($safeprojectname$.DVDCollectionDataSet.DVDsRow)rowView.Row; // check to see if UPC value is null if ((!dvdRow.IsUPCNull()) && dvdRow.UPC != "") { //variables to store and preserve custom comment and rating values string currentComments = dvdRow.Comments; int currentRating = dvdRow.MyRating; //get updated DVD object from Web service refreshedDVD = amazonService.RefreshDVDByUPC(dvdRow.UPC); //update cached image this.boxArtPictureBox.Load(refreshedDVD.ImageUrl); refreshedDVD.ImageCache = (Bitmap)this.boxArtPictureBox.Image; //convert DVD to dvdRow refreshedDVDRow = this.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 this.dvdCollectionDataSet.DVDs.LoadDataRow(refreshedDVDRow.ItemArray, LoadOption.Upsert); } } } catch (Exception ex) { MessageBox.Show(String.Format("There was a problem refreshing the data from the online Web service: {0}", ex.Message)); Debug.WriteLine(ex.ToString()); } } } /// /// 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 void ViewOnlineButton_Click(System.Object sender, System.EventArgs e) { //boundary check: make sure movie datatable is not empty if (this.dvdsDataConnector.Count > 0) { //variables to store and preserve custom comment and rating values DataRowView rowView = (DataRowView)this.dvdsDataConnector.Current; DVDCollectionDataSet.DVDsRow dvdRow = ($safeprojectname$.DVDCollectionDataSet.DVDsRow)rowView.Row; //variable to store the Web page URL value string webLink = ""; //check for null before accessing WebPageLink property if (!dvdRow.IsWebPageLinkNull()) { webLink = dvdRow.WebPageLink; } //prompts to see if end user trusts URL and stores the prompt result value string msgText = String.Format("About to view this URL in an external browser: '{0}'. Is it safe to proceed?", webLink); DialogResult yesNoResult = MessageBox.Show(msgText, "OK to browse?", MessageBoxButtons.YesNo); //start the URL path if the user approves the prompt if ((yesNoResult == DialogResult.Yes) && (webLink != "")) { Process.Start(webLink); } } } /// /// Prompts user for file to import when Clicked. /// private void ImportButton_Click(object sender, System.EventArgs e) { this.openFileDialog1.ShowDialog(); } /// /// Imports image provided by user when user clicks OK to open file prompt. /// private void OpenFileDialog1_FileOk(System.Object sender, System.ComponentModel.CancelEventArgs e) { this.ImportImage(this.openFileDialog1.FileName); } /// /// 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 internal int LoadData() { int rowsLoaded = 0; //try to fill the datatable with the query of all movies //note: if the database contains a large amount 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 { isUpdating = true; rowsLoaded = this.dvdsTableAdapter.Fill(this.dvdCollectionDataSet.DVDs); } catch (Exception ex) { MessageBox.Show(String.Format("There was a problem loading data: {0}", ex.Message)); Debug.WriteLine(ex.ToString()); } finally { isUpdating = false; } return rowsLoaded; } /// /// 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. internal int SaveData() { if (isUpdating){ return 0; } int rowsSaved = 0; //try to get changes and save to database try { //only push update to database if changes are detected if (dvdCollectionDataSet.HasChanges()) { isUpdating = true; rowsSaved = this.dvdsTableAdapter.Update(this.dvdCollectionDataSet.DVDs); } } catch { } finally { isUpdating = false; } return rowsSaved; } /// /// 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 void ApplyTextboxFilter() { try { //sets filter string WHERE clause in the form "Where COLUMNNAME like '@FilterText'" this.dvdsDataConnector.Filter = String.Format("{0} like '%{1}%'", this.dvdCollectionDataSet.DVDs.TitleColumn.ColumnName, this.filterTextBox.Text); } catch (Exception ex) { Debug.WriteLine(ex.ToString()); } } /// /// Deletes the currently selected movie after prompting the user. /// internal void DeleteCurrent() { //check for boundaries before performing delete: datatable is empty, or there is no selection if ((this.dvdsDataConnector.Count > 0) && (this.dvdsDataConnector.Current != null)) //convert generic Current object returned by DataConnector to the typed movie row object { DataRowView rowView = (DataRowView)this.dvdsDataConnector.Current; $safeprojectname$.DVDCollectionDataSet.DVDsRow dvdRow = ($safeprojectname$.DVDCollectionDataSet.DVDsRow)rowView.Row; //string representing the friendly name of the current movie to be deleted string title = "[No Title]"; //use movie title property in the typed row object if it contains valid data if ((!dvdRow.IsTitleNull()) && (dvdRow.Title != null)) { title = dvdRow.Title; } //text displayed in a prompt to the user before deleting string msgText = 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 DialogResult dialogResult = MessageBox.Show(msgText, "OK to delete?", MessageBoxButtons.YesNo); //remove the current movie if the user accepts the prompt if (dialogResult == DialogResult.Yes) { this.dvdsDataConnector.RemoveCurrent(); } //make sure we always have a row available if (dvdsDataConnector.Count == 0){ this.dvdsDataConnector.AddNew(); } } } /// /// 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 void InitRatingPickerControl() { //create rating picker control object and site it on the parent user control this.ratingPickerControl = new RatingPickerControl(); this.dvdDetailsPanel.Controls.Add(this.ratingPickerControl); //set default properties and data binding ((System.ComponentModel.ISupportInitialize)this.ratingPickerControl).BeginInit(); this.ratingPickerControl.Anchor = (System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right); this.ratingPickerControl.BackColor = System.Drawing.Color.Transparent; this.ratingPickerControl.CurrentRating = -1; this.ratingPickerControl.DataBindings.Add("CurrentRating", this.dvdsDataConnector, "MyRating", true, DataSourceUpdateMode.OnPropertyChanged, null); this.ratingPickerControl.Location = new System.Drawing.Point(128, 388); this.ratingPickerControl.Name = "RatingPickerControl1"; this.ratingPickerControl.Size = new System.Drawing.Size(80, 16); this.ratingPickerControl.TabIndex = 7; ((System.ComponentModel.ISupportInitialize)this.ratingPickerControl).EndInit(); } /// /// Imports image value into datatable from file provided by user. /// /// private void ImportImage(string filename) { try { //check for boundaries before performing delete: datatable is empty, or there is no selection if (this.dvdsDataConnector.Current != null) { //convert generic Current object returned by DataConnector to the typed movie row object DataRowView rowView = (DataRowView)this.dvdsDataConnector.Current; $safeprojectname$.DVDCollectionDataSet.DVDsRow dvdRow = ($safeprojectname$.DVDCollectionDataSet.DVDsRow)rowView.Row; //open file as Readonly from file system, copy bytes, and assign to the image property of the current row dvdRow.ImageBinary = File.ReadAllBytes(filename); this.dvdsDataConnector.ResetCurrentItem(); } } catch (Exception ex) { MessageBox.Show(String.Format("There was a problem loading the image: {0}", ex.Message)); Debug.WriteLine(ex.ToString()); } } private void HostingForm_FormClosed(System.Object sender, System.Windows.Forms.FormClosedEventArgs e){ //call EndEdit to capture all changes made in the UI this.dvdsDataConnector.EndEdit(); //when the parent form is closing, be sure to save the data on this control SaveData(); } private void ListDetails_ParentChanged(System.Object sender, System.EventArgs e){ ////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 != null){ this.hostingForm.FormClosed -= new System.Windows.Forms.FormClosedEventHandler(HostingForm_FormClosed); } this.hostingForm = (System.Windows.Forms.Form)this.ParentForm; this.hostingForm.FormClosed += new System.Windows.Forms.FormClosedEventHandler(HostingForm_FormClosed); } private void TitleTextBox_Click(System.Object sender, System.EventArgs e){ if (this.titleTextBox.Text == "[New row - select to enter details]"){ this.titleTextBox.SelectAll(); } } } }