Skip to content

Commit 27017f6

Browse files
authored
Merge pull request #192 from Nfactor26/allow-deleting-controls
Allow controls to be deleted
2 parents ad9885e + 252ddd1 commit 27017f6

File tree

20 files changed

+343
-90
lines changed

20 files changed

+343
-90
lines changed

src/Pixel.Automation.AppExplorer.ViewModels/Application/ApplicationExplorerViewModel.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,13 @@ public async Task AddApplication(KnownApplication knownApplication)
206206

207207
public async Task EditApplicationAsync(ApplicationDescriptionViewModel applicationDescriptionViewModel)
208208
{
209-
await this.eventAggregator.PublishOnUIThreadAsync(new PropertyGridObjectEventArgs(applicationDescriptionViewModel.ApplicationDetails, () => { _ = SaveApplicationAsync(applicationDescriptionViewModel); }, () => { return true; }));
209+
await this.eventAggregator.PublishOnUIThreadAsync(new PropertyGridObjectEventArgs(applicationDescriptionViewModel.ApplicationDetails,
210+
async () => {
211+
await SaveApplicationAsync(applicationDescriptionViewModel);
212+
},
213+
() => {
214+
return true;
215+
}));
210216
}
211217

212218
public async Task SaveApplicationAsync(ApplicationDescriptionViewModel applicationDescriptionViewModel)

src/Pixel.Automation.AppExplorer.ViewModels/Control/ControlExplorerViewModel.cs

Lines changed: 110 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ public void ToggleRename(ControlDescriptionViewModel targetControl)
162162
/// <param name="controlToRename"></param>
163163
public async Task RenameControl(ActionExecutionContext context, ControlDescriptionViewModel controlToRename)
164164
{
165+
string currentName = controlToRename.ControlName;
165166
try
166167
{
167168
var keyArgs = context.EventArgs as KeyEventArgs;
@@ -180,7 +181,9 @@ public async Task RenameControl(ActionExecutionContext context, ControlDescripti
180181
catch (Exception ex)
181182
{
182183
logger.Error(ex, ex.Message);
184+
controlToRename.ControlName = currentName;
183185
CanEdit = false;
186+
MessageBox.Show(ex.Message, $"Error while renaming control : {controlToRename.ControlName}");
184187
}
185188
}
186189

@@ -242,7 +245,11 @@ private IEnumerable<ControlDescriptionViewModel> LoadControlDetails(ApplicationD
242245
var controls = this.applicationDataManager.GetControlsForScreen(applicationDescriptionViewModel.Model, screenName).ToList();
243246
foreach (var control in controls)
244247
{
245-
var controlDescriptionViewModel = new ControlDescriptionViewModel(control);
248+
if(control.IsDeleted)
249+
{
250+
continue;
251+
}
252+
var controlDescriptionViewModel = new ControlDescriptionViewModel(control);
246253
applicationDescriptionViewModel.AddControl(controlDescriptionViewModel, screenName);
247254
controlsList.Add(controlDescriptionViewModel);
248255
}
@@ -276,21 +283,29 @@ public async Task MoveToScreen(ControlDescriptionViewModel controlDescription)
276283
/// <returns></returns>
277284
public async Task ConfigureControlAsync(ControlDescriptionViewModel controlToEdit)
278285
{
279-
Guard.Argument(controlToEdit).NotNull();
280-
281-
//Make a copy of ControlDescription that is opened for edit
282-
var copyOfControlToEdit = controlToEdit.ControlDescription.Clone() as ControlDescription;
283-
copyOfControlToEdit.ControlId = controlToEdit.ControlId;
284-
var controlEditor = controlEditorFactory.CreateControlEditor(controlToEdit.ControlDetails);
285-
controlEditor.Initialize(copyOfControlToEdit);
286-
var result = await windowManager.ShowDialogAsync(controlEditor);
287-
//if save was clicked, assign back changes in ControlDetails to controlToEdit.
288-
//Editor only allows editing ControlDetails. Description won't be modified.
289-
if (result.HasValue && result.Value)
286+
try
290287
{
291-
controlToEdit.ControlDetails = copyOfControlToEdit.ControlDetails;
292-
await SaveControlDetails(controlToEdit, false);
293-
await this.eventAggregator.PublishOnBackgroundThreadAsync(new ControlUpdatedEventArgs(controlToEdit.ControlId));
288+
Guard.Argument(controlToEdit).NotNull();
289+
290+
//Make a copy of ControlDescription that is opened for edit
291+
var copyOfControlToEdit = controlToEdit.ControlDescription.Clone() as ControlDescription;
292+
copyOfControlToEdit.ControlId = controlToEdit.ControlId;
293+
var controlEditor = controlEditorFactory.CreateControlEditor(controlToEdit.ControlDetails);
294+
controlEditor.Initialize(copyOfControlToEdit);
295+
var result = await windowManager.ShowDialogAsync(controlEditor);
296+
//if save was clicked, assign back changes in ControlDetails to controlToEdit.
297+
//Editor only allows editing ControlDetails. Description won't be modified.
298+
if (result.HasValue && result.Value)
299+
{
300+
controlToEdit.ControlDetails = copyOfControlToEdit.ControlDetails;
301+
await SaveControlDetails(controlToEdit, false);
302+
await this.eventAggregator.PublishOnBackgroundThreadAsync(new ControlUpdatedEventArgs(controlToEdit.ControlId));
303+
}
304+
}
305+
catch (Exception ex)
306+
{
307+
logger.Error(ex, ex.Message);
308+
MessageBox.Show(ex.Message, $"Error while configuring control : {controlToEdit.ControlName}");
294309
}
295310
}
296311

@@ -301,9 +316,43 @@ public async Task ConfigureControlAsync(ControlDescriptionViewModel controlToEdi
301316
/// <returns></returns>
302317
public async Task EditControlAsync(ControlDescriptionViewModel controlToEdit)
303318
{
304-
await this.eventAggregator.PublishOnUIThreadAsync(new PropertyGridObjectEventArgs(controlToEdit, () => { _ = SaveControlDetails(controlToEdit, false); }, () => { return true; }));
319+
await this.eventAggregator.PublishOnUIThreadAsync(new PropertyGridObjectEventArgs(controlToEdit,
320+
async () => {
321+
try
322+
{
323+
await SaveControlDetails(controlToEdit, false);
324+
}
325+
catch(Exception ex)
326+
{
327+
logger.Error(ex, "There was an error while trying to edit control : {0}", controlToEdit.ControlName);
328+
MessageBox.Show(ex.Message, $"Error while editing control : {controlToEdit.ControlName}");
329+
}
330+
},
331+
() => {
332+
return true;
333+
}));
305334
}
306335

336+
/// <summary>
337+
/// Delete the control
338+
/// </summary>
339+
/// <param name="controlToDelete"></param>
340+
public async Task DeleteControlAsync(ControlDescriptionViewModel controlToDelete)
341+
{
342+
try
343+
{
344+
Guard.Argument(controlToDelete, nameof(controlToDelete)).NotNull();
345+
await this.applicationDataManager.DeleteControlAsync(controlToDelete.ControlDescription);
346+
this.Controls.Remove(controlToDelete);
347+
}
348+
catch (Exception ex)
349+
{
350+
logger.Error(ex, "There was an error while trying to delete control : {0}", controlToDelete.ControlName);
351+
MessageBox.Show(ex.Message, $"Error while deleting control : {controlToDelete.ControlName}");
352+
}
353+
}
354+
355+
307356
/// <summary>
308357
/// Show file browse dialog and let user pick a new image for the control.
309358
/// Existing image will be deleted and replaced with the new image picked by user.
@@ -312,25 +361,33 @@ public async Task EditControlAsync(ControlDescriptionViewModel controlToEdit)
312361
/// <returns></returns>
313362
public async Task ChangeImageFromExistingAsync(ControlDescriptionViewModel selectedControl)
314363
{
315-
OpenFileDialog openFileDialog = new OpenFileDialog();
316-
openFileDialog.Filter = "PNG File (*.Png)|*.Png";
317-
openFileDialog.InitialDirectory = Environment.CurrentDirectory;
318-
if (openFileDialog.ShowDialog() == true)
364+
try
319365
{
320-
string fileName = openFileDialog.FileName;
321-
File.Delete(selectedControl.ControlImage);
322-
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
366+
OpenFileDialog openFileDialog = new OpenFileDialog();
367+
openFileDialog.Filter = "PNG File (*.Png)|*.Png";
368+
openFileDialog.InitialDirectory = Environment.CurrentDirectory;
369+
if (openFileDialog.ShowDialog() == true)
323370
{
324-
//we can't reuse the same control image name due to caching issues with bitmap which will keep using old file
325-
//unless file name changes
326-
selectedControl.ControlImage = await this.applicationDataManager.AddOrUpdateControlImageAsync(selectedControl.ControlDescription, fs);
327-
await SaveControlDetails(selectedControl, false);
328-
// This will force reload image on control explorer
329-
selectedControl.ImageSource = null;
330-
// This will force reload image on process designer
331-
await this.eventAggregator.PublishOnBackgroundThreadAsync(new ControlUpdatedEventArgs(selectedControl.ControlId));
371+
string fileName = openFileDialog.FileName;
372+
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
373+
{
374+
//we can't reuse the same control image name due to caching issues with bitmap which will keep using old file
375+
//unless file name changes
376+
selectedControl.ControlImage = await this.applicationDataManager.AddOrUpdateControlImageAsync(selectedControl.ControlDescription, fs);
377+
await SaveControlDetails(selectedControl, false);
378+
// This will force reload image on control explorer
379+
selectedControl.ImageSource = null;
380+
// This will force reload image on process designer
381+
await this.eventAggregator.PublishOnBackgroundThreadAsync(new ControlUpdatedEventArgs(selectedControl.ControlId));
382+
}
383+
File.Delete(selectedControl.ControlImage);
332384
}
333385
}
386+
catch (Exception ex)
387+
{
388+
logger.Error(ex, "There was an error while trying to change image for control : {0}", selectedControl.ControlName);
389+
MessageBox.Show(ex.Message, $"Error while changing image for control : {selectedControl.ControlName}");
390+
}
334391
}
335392

336393
/// <summary>
@@ -353,7 +410,8 @@ public async Task CloneControl(ControlDescriptionViewModel controlToClone)
353410
}
354411
catch (Exception ex)
355412
{
356-
logger.Error(ex, "There was an error while trying to clone the control.");
413+
logger.Error(ex, "There was an error while trying to clone control : {0}", selectedControl.ControlName);
414+
MessageBox.Show(ex.Message, $"Error while cloning control : {selectedControl.ControlName}");
357415
}
358416
}
359417

@@ -363,18 +421,26 @@ public async Task CloneControl(ControlDescriptionViewModel controlToClone)
363421
/// <param name="controlToRename"></param>
364422
public async Task CreateRevision(ControlDescriptionViewModel control)
365423
{
366-
Guard.Argument(control).NotNull();
367-
368-
var clonedControl = control.ControlDescription.Clone() as ControlDescription;
369-
clonedControl.ControlId = control.ControlId;
370-
clonedControl.Version = new Version(control.Version.Major + 1, 0);
371-
var controlDescriptionViewModel = new ControlDescriptionViewModel(clonedControl);
372-
await SaveBitMapSource(controlDescriptionViewModel.ControlDescription, controlDescriptionViewModel.ImageSource);
373-
await SaveControlDetails(controlDescriptionViewModel, true);
374-
//we remove the visible version and add the new revised version in explorer.
375-
this.Controls.Remove(control);
376-
this.Controls.Add(controlDescriptionViewModel);
377-
logger.Information("Created a new revision for control : {0}", control.ControlDescription);
424+
try
425+
{
426+
Guard.Argument(control).NotNull();
427+
428+
var clonedControl = control.ControlDescription.Clone() as ControlDescription;
429+
clonedControl.ControlId = control.ControlId;
430+
clonedControl.Version = new Version(control.Version.Major + 1, 0);
431+
var controlDescriptionViewModel = new ControlDescriptionViewModel(clonedControl);
432+
await SaveBitMapSource(controlDescriptionViewModel.ControlDescription, controlDescriptionViewModel.ImageSource);
433+
await SaveControlDetails(controlDescriptionViewModel, true);
434+
//we remove the visible version and add the new revised version in explorer.
435+
this.Controls.Remove(control);
436+
this.Controls.Add(controlDescriptionViewModel);
437+
logger.Information("Created a new revision for control : {0}", control.ControlDescription);
438+
}
439+
catch (Exception ex)
440+
{
441+
logger.Error(ex, "There was an error while creating revision of control : {0}", selectedControl.ControlName);
442+
MessageBox.Show(ex.Message, $"Error while creating revision for control : {selectedControl.ControlName}");
443+
}
378444
}
379445

380446
private readonly object locker = new object();

src/Pixel.Automation.AppExplorer.Views/Control/ControlExplorerView.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
<MenuItem x:Name="CreateRevision" Header="Create Revision" cal:Action.TargetWithoutContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type Grid}, AncestorLevel=2}}" cal:Message.Attach="[Event Click] = [Action CreateRevision($dataContext)]"></MenuItem>
7777
<MenuItem x:Name="ChangeImage" Header="Change Image" cal:Action.TargetWithoutContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type Grid}, AncestorLevel=2}}" cal:Message.Attach="[Event Click] = [Action ChangeImageFromExistingAsync($dataContext)]"></MenuItem>
7878
<MenuItem x:Name="MoveToScreen" Header="Move To Screen" cal:Action.TargetWithoutContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type Grid}, AncestorLevel=2}}" cal:Message.Attach="[Event Click] = [Action MoveToScreen($dataContext)]"></MenuItem>
79+
<MenuItem x:Name="Delete" Header="Delete" cal:Action.TargetWithoutContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type Grid}, AncestorLevel=2}}" cal:Message.Attach="[Event Click] = [Action DeleteControlAsync($dataContext)]" ></MenuItem>
7980
</StackPanel>
8081
</ControlTemplate>
8182
</ContextMenu.Template>

src/Pixel.Automation.Core/Controls/ControlDescription.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ public class ControlDescription : ICloneable
5454
[DataMember(Order = 100)]
5555
public IControlIdentity ControlDetails { get; set; }
5656

57+
/// <summary>
58+
/// Indicates if the Control was deleted.
59+
/// </summary>
60+
[DataMember(Order = 1000)]
61+
public bool IsDeleted { get; set; }
62+
5763
/// <summary>
5864
/// Default constructor
5965
/// </summary>

src/Pixel.Automation.Designer.ViewModels/AutomationBuilder/EditorViewModel.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -411,9 +411,17 @@ public async Task HandleAsync(TestEntityRemovedEventArgs removedEntity, Cancella
411411
/// <returns></returns>
412412
public async Task HandleAsync(ControlAddedEventArgs control, CancellationToken cancellationToken)
413413
{
414-
var controlDescription = control.Control;
415-
var referenceManager = this.projectManager.GetReferenceManager();
416-
await referenceManager.AddControlReferenceAsync(new ControlReference(controlDescription.ApplicationId, controlDescription.ControlId, controlDescription.Version));
414+
var controlDescription = control.Control;
415+
try
416+
{
417+
var referenceManager = this.projectManager.GetReferenceManager();
418+
await referenceManager.AddControlReferenceAsync(new ControlReference(controlDescription.ApplicationId, controlDescription.ControlId, controlDescription.Version));
419+
}
420+
catch (Exception ex)
421+
{
422+
logger.Error(ex, "There was an error while trying to add control reference for control : {0}", controlDescription.ControlName);
423+
MessageBox.Show(ex.Message, $"Error while adding control : {controlDescription.ControlName}");
424+
}
417425
}
418426

419427

src/Pixel.Automation.Designer.ViewModels/PropertyGrid/PropertyGridViewModel.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ public PropertyGridViewModel()
3333
this.SaveCommand = new RelayCommand(p => Save(), p => CanSave());
3434
}
3535

36-
public void SetState(object selectedObject, bool isReadOnly, Action saveCommand, Func<bool> canSave)
36+
public void SetState(object selectedObject, bool isReadOnly, Func<Task> saveCommand, Func<bool> canSave)
3737
{
3838
this.selectedObject = selectedObject;
3939
this.isReadOnly = isReadOnly;
40-
this.onSave = saveCommand;
40+
this.onSave = () => saveCommand();
4141
this.canSave = canSave;
4242
NotifyOfPropertyChange(() => SelectedObject);
4343
NotifyOfPropertyChange(() => IsReadOnly);

src/Pixel.Automation.Editor.Notifications/EventArgs/PropertyGridObjectEventArgs.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ public class PropertyGridObjectEventArgs : EventArgs
66

77
public bool IsReadOnly { get; private set; }
88

9-
public Action SaveCommand { get; private set; }
9+
public Func<Task> SaveCommand { get; private set; }
1010

1111
public Func<bool> CanSaveCommand { get; private set; }
1212

@@ -21,7 +21,7 @@ public PropertyGridObjectEventArgs(Object objectToDisplay, bool isReadOnly) : ba
2121
this.IsReadOnly = isReadOnly;
2222
}
2323

24-
public PropertyGridObjectEventArgs(Object objectToDisplay, Action saveCommand, Func<bool> canSaveCommand) : this(objectToDisplay, false)
24+
public PropertyGridObjectEventArgs(Object objectToDisplay, Func<Task> saveCommand, Func<bool> canSaveCommand) : this(objectToDisplay, false)
2525
{
2626
this.SaveCommand = saveCommand;
2727
this.CanSaveCommand = canSaveCommand;

src/Pixel.Automation.Reference.Manager/ReferenceManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,11 @@ public async Task AddControlReferenceAsync(ControlReference controlReference)
127127
Guard.Argument(controlReference, nameof(controlReference)).NotNull();
128128
if (!this.controlReferences.HasReference(controlReference))
129129
{
130-
this.controlReferences.AddControlReference(controlReference);
131130
if (IsOnlineMode)
132131
{
133132
await this.referencesRepositoryClient.AddOrUpdateControlReferences(this.projectId, this.projectVersion, controlReference);
134133
}
134+
this.controlReferences.AddControlReference(controlReference);
135135
SaveLocal();
136136
}
137137
}

0 commit comments

Comments
 (0)