Reputation: 387
I am trying to update multiple values in a list box using this method: What this method does is copy the contents of the specified directory but it outputs the current file name to the background worker progress changed event.
private bool CopyDirectory(string SourcePath, string DestinationPath, bool Recursive, BackgroundWorker worker, DoWorkEventArgs e)
{
List<string> Paths = new List<string>();
List<string> Files = new List<string>();
//for windows xp My documents
if(!Directory.Exists(SourcePath))
{
SourcePath = SourcePath.Replace(@"C$\Users\", @"C$\Documents and Settings");
int doccount = Regex.Matches(SourcePath, "Documents").Count;
//if source contains 2 documents
if(doccount > 1)
{
ReplaceLastOccurrence(SourcePath, "Documents", "My Documents");
}
}
//set file permissions
FileIOPermission f2 = new FileIOPermission(FileIOPermissionAccess.Read, SourcePath);
f2.AllLocalFiles = FileIOPermissionAccess.Read;
f2.Demand();
foreach (string StringPath in DirectoryList(SourcePath, Recursive, null))
Paths.Add(StringPath);
foreach (string StringPath in FileList(SourcePath, Recursive, null))
Files.Add(StringPath);
try
{
foreach (string dirPath in Paths)
System.IO.Directory.CreateDirectory(dirPath.Replace(SourcePath, DestinationPath));
foreach (string newPath in Files)
{
string[] filename = newPath.Split('$');
string currentfile = "C:" + filename[1];
//report the file name to the background worker
worker.ReportProgress(0, currentfile);
System.IO.File.Copy(newPath, newPath.Replace(SourcePath, DestinationPath), Recursive);
}
return true;
}
catch { return false; }
}
private static List<string> FileList(string RootDirectory,
bool SearchAllDirectories, Predicate<string> Filter)
{
List<string> retList = new List<string>();
try
{
List<string> DirList = new List<string> { RootDirectory };
if (SearchAllDirectories)
DirList.AddRange(DirectoryList(RootDirectory, SearchAllDirectories, Filter));
foreach (string DirectoryStr in DirList)
{
DirectoryInfo di = new DirectoryInfo(DirectoryStr);
try
{
foreach (FileInfo FileStr in di.EnumerateFiles())
{
try
{
if ((Filter == null) || (Filter(FileStr.FullName)))
retList.Add(FileStr.FullName);
}
catch (Exception) { }
}
}
catch (UnauthorizedAccessException) { }
catch (Exception) { }
}
}
catch (Exception) { }
return retList;
}
private static List<string> DirectoryList(string RootDirectory,
bool SearchAllDirectories, Predicate<string> Filter)
{
List<string> retList = new List<string>();
try
{
DirectoryInfo di = new DirectoryInfo(RootDirectory);
foreach (DirectoryInfo DirectoryStr in di.EnumerateDirectories())
{
try
{
if ((Filter == null) || (Filter(DirectoryStr.FullName)))
{
retList.Add(DirectoryStr.FullName);
if (SearchAllDirectories)
retList.AddRange(DirectoryList(DirectoryStr.FullName, SearchAllDirectories,
Filter));
}
}
catch (UnauthorizedAccessException) { }
catch (Exception) { }
}
}
catch (Exception) { }
return retList;
}
This works great for just one file name update, however, my program will do multiple copying of directors that i wish to update a list-view item to display it to the user.
private void bgwBackup_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.InvokeEx(c => this.lblBackupStatus.Text = e.UserState.ToString());
}
My question is how would I update multiple listviewitems with the current filename of the specified path ? I can post my do work handler if needed. Thank you.
EDIT1 Here is my DO_WORK as requested:
private void bgwBackup_DoWork(object sender, DoWorkEventArgs e)
{
//Textbox Array Values
// 0 = computername
// 1 = username
// 2 = password
string[] tbvalues = (string[])e.Argument;
string computer = tbvalues[0];
string user = tbvalues[1];
string pass = tbvalues[2];
try
{
//AD SEARCH
DirectoryEntry de = new DirectoryEntry("WinNT://" + Environment.UserDomainName + "/" + user);
string homepath = de.Properties["homedirectory"].Value.ToString();
if (string.IsNullOrWhiteSpace(homepath))
{
//do something when home drive is missing
MessageBox.Show("NO H DRIVE");
}
else
{
//Declare strings
string os = GetOsName(computer);
string desktop="";
string documents="";
string favorites="";
string outlooksig = "";
string outlookcache = "";
string hdriveroot = homepath + @"\PKBACKUP " + DateTime.Now.ToString("MM-dd-yyyy--hh-mm-ss");
string hudp = hdriveroot + @"\Desktop";
string hudoc = hdriveroot + @"\Documents";
string hufav = hdriveroot + @"\Favorites";
string hprintdir = hdriveroot + @"\printers\";
string outlooksigdir = hdriveroot + @"\Outlook Files\Signatures";
string outlookcachedir = hdriveroot + @"\Outlook Files\Cache";
if (os.Contains("XP"))
{
desktop = @"\\" + computer + @"\C$\Documents and Settings\" + user + @"\Desktop";
documents = @"\\" + computer + @"\C$\Documents and Settings\" + user + @"\My Documents";
favorites = @"\\" + computer + @"\C$\Documents and Settings\" + user + @"\Favorites";
//outlook signatures
outlooksig = @"\\" + computer + @"\C$\Documents and Settings\" + user + @"\Application Data\Microsoft\Signatures";
//outlook cache
outlookcache = @"\\" + computer + @"\C$\Documents and Settings\" + user + @"\Application Data\Microsoft\Outlook";
}
else
{
desktop = @"\\" + computer + @"\C$\Users\" + user + @"\Desktop";
documents = @"\\" + computer + @"\C$\Users\" + user + @"\Documents";
favorites = @"\\" + computer + @"\C$\Users\" + user + @"\Favorites";
outlooksig = @"\\" + computer + @"\C$\Users\" + user + @"\AppData\Roaming\Microsoft\Signatures";
outlookcache = @"\\" + computer + @"\C$\Users\" + user + @"\AppData\Roaming\Microsoft\Outlook";
}
//Copy Files
using (new Impersonator(user, "Domain.org", pass))
{
string outlookext = "nk2";
CopyDirectory(favorites, hufav, true, bgwBackup, e);
CopyDirectory(documents, hudoc, true, bgwBackup, e);
CopyDirectory(desktop, hudp, true, bgwBackup, e);
CopyDirectory(outlooksig, outlooksigdir, true, bgwBackup, e);
copybyext(outlookcache, outlookcachedir, outlookext, user); //copy nk2 file method
//Printers
List<string> printers = new List<string>();
foreach (string printername in lbBackupprinters.Items)
{
if (printername.Contains("No Printers Found"))
{
//Add listview entry that no printers were found
}
else
{
if (Directory.Exists(hprintdir) == false)
{
Directory.CreateDirectory(hprintdir);
}
string prntsvr;
string printer;
//strip out numbers in string
prntsvr = Regex.Replace(printername, "[^0-9]+", string.Empty);
//take the first number in the string
prntsvr = prntsvr[0].ToString();
//remote everything before last comma
printer = printername.Substring(printername.LastIndexOf(',') + 1);
//add vbs to printer name
printer = printer + ".vbs";
//get file path of printer vbs script
string[] printerpaths = Directory.GetFiles(@"\\dist-win-prnt-" + prntsvr + @"\printerscripts", printer);
//append string builder with print server path
if (!File.Exists(printerpaths[0]))
{
//do something if the printer does not exist, add error.
}
else
{
printers.Add(printerpaths[0]);
}
}
string defaultprinter = lbBackupprinters.Items[0].ToString() + ".vbs";
defaultprinter = defaultprinter.Substring(defaultprinter.LastIndexOf(',') + 1);
//
//Download printer vbs script(s)
foreach (string printstring in printers)
{
string hprintfilename = printstring.Substring(printstring.LastIndexOf("\\") + 1);
if (hprintfilename.Equals(defaultprinter))
{
File.Copy(printstring, hprintdir + "(Defualt) "+ hprintfilename, true);
}
else
{
File.Copy(printstring, hprintdir + hprintfilename, true);
}
}
} // end else
}
}
} //end try
catch (Win32Exception logonfail)
{
MessageBox.Show("LOGON FAIL" + logonfail);
//add label for failure
return;
}
catch (DirectoryServicesCOMException adfail)
{
MessageBox.Show(adfail.ToString());
}
catch (UnauthorizedAccessException accessex)
{
MessageBox.Show(accessex.ToString());
}
}
EDIT2: Image of program
EDIT3: Here is my progress changed and completed code
//this only updates the status text and does not update the listview control.
private void bgwBackup_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.InvokeEx(c => this.lblBackupStatus.Text = e.UserState.ToString());
}
private void bgwBackup_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lblBackupStatus.Text = "Backup job completed";
}`
Upvotes: 3
Views: 2856
Reputation: 4733
First, add another class
class BackupTask
{
public string MachineName { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string CurrentFile { get; set; }
public int OverallProgress { get; set; }
}
Then
private List<BackupTask> task_definitions = new List<BackupTask>(); //this is needed to parallel foreach
private List<BackupTask> tasks = new List<BackupTask>(); //this is what you will use to report progress of your copying
and suppose your backgroundworker is named 'bw`
private BackgroundWorker bw;
Add this to your XAML file (before main Grid)
<Window.Resources>
<DataTemplate x:Key="BackupTask">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding MachineName}" Margin="2,4,2,4"/>
<TextBlock Text="{Binding Username}" Margin="2,4,2,4" />
<TextBlock Text="{Binding Password}" Margin="2,4,2,4"/>
<TextBlock Text="{Binding CurrentFile}" Margin="2,4,2,4"/>
<TextBlock Text="{Binding OverallProgress}" Margin="2,4,2,4"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
in your listview set ItemTemplate="{StaticResource ResourceKey=BackupTask}
So in the window constructor
bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
Your buttons
private void btn_AddToQueue_Click(object sender, RoutedEventArgs e)
{
BackupTask bt = new BackupTask();
bt.MachineName = //load these
bt.Username = // from your
bt.Password = //textboxes
bt.CurrentFile = "";
bt.OverallProgress = 0;
AddOrModifyTask(bt);
listView1.ItemsSource = tasks;
}
private void btn_StartBackup_Click(object sender, RoutedEventArgs e)
{
if (!bw.IsBusy)
bw.RunWorkerAsync();
}
Of cource you will also need
void AddOrModifyTask(BackupTask t)
{
bool found = false;
foreach (BackupTask bt in tasks)
{
if (bt.MachineName == t.MachineName)
{
found = true;
bt.CurrentFile = t.CurrentFile;
bt.OverallProgress = t.OverallProgress;
}
}
if (!found)
tasks.Add(t);
}
Your progressbar events
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lock (tasks)
{
AddOrModifyTask((BackupTask)e.UserState);
}
listView1.ItemsSource = tasks;
listView1.Items.Refresh();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
task_definitions = tasks;
Parallel.ForEach(task_definitions, task =>
{
string computer = task.MachineName;
string user = task.Username;
string pass = task.Password;
//your old Do_Work code
});
}
Instead of passing background worker as parameter pass associated BackupTask object and always use bw
Quick working example is here
Upvotes: 5