I had not originally planned to implement the BusyIndicator, but I realized that my Powershell script takes some time to execute, which may cause confusion with a user. There do not seem to be any tutorials out there showing how to utilize the BusyIndicator with Powershell scripts in C#. This is a great tutorial since it was written by the author of the WPF Extended Toolkit, but it's not for what I need.
Here is what I have. Code is truncated for the sake of brevity:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void imageBtn_Click(object sender, RoutedEventArgs e)
{
Button imgBtn = sender as Button;
string appToCheck = GetSubString(imgBtn.Name);
switch(appToCheck)
{
case "weather":
InvokePowerShell(appToCheck);
break;
case "news":
//DO THE SAME FOR ALL CASES
break;
//17 more cases follow
}
}
private string GetSubString(string buttonName)
{
int index = buttonName.IndexOf('B');
return buttonName.Substring(0, index);
}
private void InvokePowerShell(string str)
{
str = char.ToUpper(str[0]) + str.Substring(1);
PowerShell ps = PowerShell.Create();
ps.AddScript("Get-AppxPackage | Select Name | Where-Object ($_.Name -like '*" + str + "*'}");
_busyIndicator.IsBusy = true;
ps.BeginInvoke<PSObject>(null, new PSInvocationSettings(), ar =>
{
try
{
var psOutput = ps.EndInvoke(ar);
this.Dispatcher.Invoke(() => _busyIndicator.IsBusy = false);
foreach (PSObject item in psOutput)
{
if (item.Equals(String.Empty))
{
MessageBox.Show(str + " is not installed so cannot be removed.");
}
else
{
if (MessageBox.Show("This cannot be undone.\nContinue?", "Warning", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.No)
{
//DO NOTHING
}
else
{
//TODO Remove the app
MessageBox.Show(str + " successfully removed.");
}
}
}
}
finally
{
//dispose of it
ps.Dispose();
}
}, null);
}
}
}
I already have the BusyIndicator set up in my XAML:
<toolkit:BusyIndicator x:Name="_busyIndicator" IsBusy="False" BusyContent="One moment....">
<!-- Insert the rest of my markup here -->
</toolkit:BusyIndicator>
I will also have an even longer method to remove everything that's listed in the app, so I will definitely want the indicator. I tried to follow the tutorial given in the link above, but I ran into a problem with my foreach loop going out of scope.
I tried to use the asynchronous BeginInvoke() method to no avail. The busy indicator just kept going, like so:
PSDataCollection<PSObject> outputCollection = new PSDataCollection<PSObject>();
IAsyncResult result = PowerShellInstance.BeginInvoke<PSObject>(outputCollection);
while (result.IsCompleted == false)
{
_busyIndicator.IsBusy = true;
}
//Then my foreach loop shown above with the if statements and MessageBox notifications
I'm very new to this. Any help would be greatly appreciated.
You can either run your code on serapate thread (with Task.Run
or similar construct), or use BeginInvoke
like this:
private void InvokePowerShell(string str) {
str = char.ToUpper(str[0]) + str.Substring(1);
// remove using, or move to a field
PowerShell ps = PowerShell.Create();
ps.AddScript("Get-AppxPackage | Select Name | Where-Object {$_.Name -like '*" + str + "*'}");
//This is where the app pauses slightly and I need a busyindicator
_busyIndicator.IsBusy = true;
ps.BeginInvoke<PSObject>(null, new PSInvocationSettings(), ar => {
try {
var psOutput = ps.EndInvoke(ar);
// note, you are not on UI thread here
this.Dispatcher.Invoke(() => _busyIndicator.IsBusy = false);
// the rest of your code here
}
finally {
// if did not move to a field - dispose here
ps.Dispose();
}
}, null);
}