/*=========================*/ #endregion #region Dialog-related Methods /*=========================*/ /// <summary> /// /// </summary> protected void Dialog_Open <TableT, RowT> ( FloatingDialog dialog, ListTable listTable, ListViewItem clickedItem, bool allowBatch, Func <RowT, bool, string> dialogTitle, Func <RowT, bool, string> dialogTooltip, Func <DataColumn, object> batchFlatten ) where TableT : DataTable, new() where RowT : DataRow { // When a single item is clicked, select it if (clickedItem != null && clickedItem.DataContext != null && !listTable.ListView.SelectedItems.Contains(clickedItem.DataContext)) { listTable.ListView.SelectedItems.Clear(); clickedItem.IsSelected = true; } bool batch = listTable.ListView.SelectedItems.Count > 1; if (!allowBatch) { MainWindow.MessageBoxError("You cannot edit more than one item at a time.", null); return; } RowT[] targetRows = new RowT[listTable.ListView.SelectedItems.Count]; try { listTable.ListView.SelectedItems.CopyTo(targetRows, 0); } catch (InvalidCastException) { MainWindow.MessageBoxError("To edit multiple items, select items of the same type.", null); return; } RowT controlRow = Dialog_MakeEditVersion <TableT, RowT>(targetRows, batchFlatten); // Show the dialog dialog.Title = dialogTitle != null?dialogTitle(controlRow, batch) : "Editing " + typeof(RowT).Name; dialog.TitleTooltip = dialogTooltip != null?dialogTooltip(controlRow, batch) : null; dialog.BeginEdit(controlRow, targetRows.Length > 1 ? (object)targetRows : (object)targetRows[0]); }
/// <summary> /// /// </summary> protected static void Dialog_AppliedChanges <RowT>(FloatingDialog dialog, string editingDialogTitle, ListView hostListView, int minPosition, CancelRoutedEventArgs e) where RowT : DataRow { // All went well, so just accept changes RowT[] targetRows = dialog.TargetContent is RowT ? new RowT[] { dialog.TargetContent as RowT } : dialog.TargetContent as RowT[]; RowT finalRow = dialog.IsBatch ? null : targetRows[0]; targetRows[0].Table.AcceptChanges(); (dialog.Content as RowT).AcceptChanges(); // Add to the table if (!dialog.IsBatch && finalRow.RowState == DataRowState.Added) { ObservableCollection <DataRow> items = hostListView.ItemsSource as ObservableCollection <DataRow>; // -2 because we already added the row to the table. We want the position of the last available int newIndex = finalRow.Table.Rows.Count > 1 ? items.IndexOf(finalRow.Table.Rows[finalRow.Table.Rows.Count - 2]) + 1 : minPosition; if (newIndex >= 0) { // Insert a new row to the items only if a new position has been found items.Insert(newIndex, finalRow); hostListView.SelectedIndex = newIndex; hostListView.ScrollIntoView(finalRow); } } foreach (RowT row in targetRows) { if (row is IPropertyChangeNotifier) { (row as IPropertyChangeNotifier).OnAllPropertiesChanged(); } } if (!dialog.IsBatch) { dialog.Title = editingDialogTitle; } }
/// <summary> /// /// </summary> /// <param name="dialog"></param> /// <returns></returns> protected static bool MessageBoxPromptForCancel(FloatingDialog dialog) { DataRow row = dialog.Content as DataRow; if (row == null) { return(false); } if (row.Table.GetChanges() == null) { return(false); } MessageBoxResult result = MessageBox.Show( "Discard changes?", "Confirm", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel); return(result == MessageBoxResult.Cancel); }
/// <summary> /// /// </summary> protected static void Dialog_AppliedChanges <RowType>(FloatingDialog dialog, string editingDialogTitle, ListView hostListView, CancelRoutedEventArgs e) where RowType : DataRow { Dialog_AppliedChanges <RowType>(dialog, editingDialogTitle, hostListView, 0, e); }
/// <summary> /// /// </summary> /// <param name="async">When true, runs the specified server method in a seperate thread.</param> /// <param name="postApplying"> /// If specified, this function is called after applying is complete. It is the /// function's responsibility to call FloatingDialog.EndApplyChanges() in order to complete the apply cycle. /// </param> protected static void Dialog_ApplyingChanges <TableType, RowType>(TableType sourceTable, FloatingDialog dialog, MethodInfo saveMethod, CancelRoutedEventArgs e, object[] additionalArgs, bool async, Action postApplying) where TableType : DataTable, new() where RowType : DataRow { RowType editVersion = dialog.Content as RowType; DataTable changes = editVersion.Table.GetChanges(); // No changes were made, skip the apply (but don't cancel) if (changes == null) { e.Skip = true; if (postApplying != null) { postApplying(); } else { dialog.EndApplyChanges(e); } return; } // Remember data state DataRowState state = changes.Rows[0].RowState; // Will store updated data TableType savedVersion = null; object[] actualArgs = additionalArgs != null? new object[additionalArgs.Length + 1] : new object[1]; actualArgs[0] = Oltp.Prepare <TableType>(changes); if (additionalArgs != null) { additionalArgs.CopyTo(actualArgs, 1); } // Save the changes to the DB Delegate[] delegates = new Delegate[] { (Action) delegate() { using (OltpProxy proxy = new OltpProxy()) { savedVersion = (TableType)saveMethod.Invoke(proxy.Service, actualArgs); } }, (Func <Exception, bool>) delegate(Exception ex) { // Failed, so cancel and display a message MessageBoxError("Error while updating.", ex); e.Cancel = true; return(false); }, (Action) delegate() { // Special case when adding a new row if (state == DataRowState.Added) { // Import the saved row sourceTable.ImportRow(savedVersion.Rows[0]); // Even though nothing needs to be updated, mark it as added so AppliedChanges handled treats it properly RowType newRow = sourceTable.Rows[sourceTable.Rows.Count - 1] as RowType; newRow.SetAdded(); // Set as new target content dialog.TargetContent = newRow; dialog.Content = Dialog_MakeEditVersion <TableType, RowType>(sourceTable, newRow); } // Activate the post applying action if (postApplying != null) { postApplying(); } else { dialog.EndApplyChanges(e); } } }; if (async) { App.CurrentPage.Window.AsyncOperation(delegates[0] as Action, delegates[1] as Func <Exception, bool>, delegates[2] as Action); } else { bool exception = false; try { (delegates[0] as Action).Invoke(); } catch (Exception ex) { (delegates[1] as Func <Exception, bool>).Invoke(ex); exception = true; } if (!exception) { (delegates[2] as Action).Invoke(); } if (postApplying != null) { postApplying(); } else { dialog.EndApplyChanges(e); } } }
protected static void Dialog_ApplyingChanges <TableType, RowType>(TableType sourceTable, FloatingDialog dialog, MethodInfo saveMethod, CancelRoutedEventArgs e, object[] additionalArgs) where TableType : DataTable, new() where RowType : DataRow { Dialog_ApplyingChanges <TableType, RowType>(sourceTable, dialog, saveMethod, e, additionalArgs, false, null); }
/// <summary> /// /// </summary> /// <param name="async">When true, runs the specified server method in a seperate thread.</param> /// <param name="postApplying"> /// If specified, this function is called after applying is complete. It is the /// function's responsibility to call FloatingDialog.EndApplyChanges() in order to complete the apply cycle. /// </param> protected static void Dialog_ApplyingChanges <TableT, RowT> ( TableT sourceTable, FloatingDialog dialog, MethodInfo saveMethod, CancelRoutedEventArgs e, object[] additionalArgs, bool async, Action postApplying ) where TableT : DataTable, new() where RowT : DataRow { RowT controlRow = dialog.Content as RowT; DataTable changes = controlRow.Table.GetChanges(); // No changes were made, skip the apply (but don't cancel) if (changes == null) { e.Skip = true; if (postApplying != null) { postApplying(); } else { dialog.EndApplyChanges(e); } return; } if (dialog.IsBatch) { // Copy all target rows and apply the changed values to them TableT clonedTargetTable = new TableT(); foreach (RowT row in (IEnumerable)dialog.TargetContent) { clonedTargetTable.ImportRow(row); } clonedTargetTable.AcceptChanges(); dialog.ApplyBindingsToItems(clonedTargetTable.Rows); // Get these changes changes = clonedTargetTable.GetChanges(); } // No changes were made, skip the apply (but don't cancel) if (changes == null) { e.Skip = true; if (postApplying != null) { postApplying(); } else { dialog.EndApplyChanges(e); } return; } // Remember data state DataRowState state = controlRow.RowState; // Will store updated data TableT savedVersion = null; // Create a typed version of the changes object[] actualArgs = additionalArgs != null? new object[additionalArgs.Length + 1] : new object[1]; actualArgs[0] = Oltp.Prepare <TableT>(changes); if (additionalArgs != null) { additionalArgs.CopyTo(actualArgs, 1); } // Save the changes to the DB Delegate[] delegates = new Delegate[] { (Action) delegate() { using (OltpProxy proxy = new OltpProxy()) { savedVersion = (TableT)saveMethod.Invoke(proxy.Service, actualArgs); } }, (Func <Exception, bool>) delegate(Exception ex) { // Failed, so cancel and display a message MainWindow.MessageBoxError("Error while updating.\n\nChanges may have been saved, if re-saving doesn't work please refresh the page.", ex); e.Cancel = true; return(false); }, (Action) delegate() { // Special case when adding a new row if (!dialog.IsBatch && state == DataRowState.Added) { // Import the saved row sourceTable.ImportRow(savedVersion.Rows[0]); // Even though nothing needs to be updated, mark it as added so AppliedChanges handled treats it properly RowT newRow = sourceTable.Rows[sourceTable.Rows.Count - 1] as RowT; newRow.SetAdded(); // Set as new target content dialog.TargetContent = newRow; dialog.Content = Dialog_MakeEditVersion <TableT, RowT>(newRow); } // Activate the post applying action if (postApplying != null) { postApplying(); } else { dialog.EndApplyChanges(e); } } }; if (async) { App.CurrentPage.Window.AsyncOperation( delegates[0] as Action, // out-of-ui action delegates[1] as Func <Exception, bool>, // exception handler delegates[2] as Action // in-ui action ); } else { bool exception = false; try { // out-of-ui action, done in ui because async is not required (delegates[0] as Action).Invoke(); } catch (Exception ex) { // exception handler (delegates[1] as Func <Exception, bool>).Invoke(ex); exception = true; } // in-ui action if (!exception) { (delegates[2] as Action).Invoke(); } if (postApplying != null) { postApplying(); } else { dialog.EndApplyChanges(e); } } }
protected static void Dialog_ApplyingChanges <TableT, RowT>(TableT sourceTable, FloatingDialog dialog, MethodInfo saveMethod, CancelRoutedEventArgs e) where TableT : DataTable, new() where RowT : DataRow { Dialog_ApplyingChanges <TableT, RowT>(sourceTable, dialog, saveMethod, e, null, false, null); }