Click here to Skip to main content
15,942,710 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am converting a number areas in my application to use asynchronous code.
My main objective is to enable the observable collection to show each add/update in the UI as it occurs, rather than wait until all done.

I have a problem in that when I try to do this by making the attached code async it will not allow me to put in an await. It comes up to say cant have an await on a void.

Can anyone modify this code to show how to do it. It would be much appreciated.

C#
<pre>
		 addin
		{
			// Loop through Files and display data while building Observable Collection
			foreach(string file in files)
			{
				// Get the original FileName
				string fileName = Path.GetFileName(file);

				// Separate Path from FileName
				string filePath = file.Replace(fileName, "");

				// Display and Load Rename Observable Collection with Original File Name

				Gbl.rO.Add(new RenameObservable(fileName, "", "Orig Loaded", true, true, filePath, file));
			}
			return true;
		}


It is executed from the following.

C#
Common.DisplayOriginalFiles(selectedFiles);


The Observable collection is defined as follows. By the way is there a simpler way to define the collection?

C#
{
		public RenameObservableCollection() : base()
		{
		}
	}

	public class RenameObservable : INotifyPropertyChanged
	{
		// Rename Display Fields
		private string originalName;

		private string newName;
		private string renameStatus;
		private bool secondPass = false;
		private bool dontRename = false;

		// Storage Fields
		private string originalNamePath;

		private string originalFileNameWithPath;

		public RenameObservable(
			string OriginalName,
			string NewName,
			string RenameStatus,
			bool SecondPass,
			bool DontRename,

			string OriginalNamePath,
			string OriginalFileNameWithPath)
		{
			this.originalName = OriginalName;
			this.newName = NewName;
			this.renameStatus = RenameStatus;
			this.secondPass = SecondPass;
			this.dontRename = DontRename;

			this.originalNamePath = OriginalNamePath;
			this.originalFileNameWithPath = OriginalFileNameWithPath;
		}

		public event PropertyChangedEventHandler PropertyChanged;

		public void NotifyPropertyChanged(string propName)
		{ this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); }

		public bool DontRename
		{
			get { return dontRename; }
			set
			{
				if (this.dontRename != value)
				{
					this.dontRename = value;
					this.NotifyPropertyChanged("DontRename");
				}
			}
		}

		public bool SecondPass
		{
			get { return secondPass; }
			set
			{
				if (this.secondPass != value)
				{
					this.secondPass = value;
					this.NotifyPropertyChanged("SecondPass");
				}
			}
		}

		public string OriginalName
		{
			get { return this.originalName; }
			set
			{
				if (this.originalName != value)
				{
					this.originalName = value;
					this.NotifyPropertyChanged("OriginalName");
				}
			}
		}

		public string NewName
		{
			get { return this.newName; }
			set
			{
				if (this.newName != value)
				{
					this.newName = value;
					this.NotifyPropertyChanged("NewName");
				}
			}
		}

		public string RenameStatus
		{
			get { return renameStatus; }
			set
			{
				if (this.renameStatus != value)
				{
					this.renameStatus = value;
					this.NotifyPropertyChanged("RenameStatus");
				}
			}
		}

		public string OriginalNamePath
		{
			get { return this.originalNamePath; }
			set
			{
				if (this.originalNamePath != value)
				{
					this.originalNamePath = value;
					this.NotifyPropertyChanged("OriginalNamePath");
				}
			}
		}

		public string OriginalFileNameWithPath
		{
			get { return this.originalFileNameWithPath; }
			set
			{
				if (this.originalFileNameWithPath != value)
				{
					this.originalFileNameWithPath = value;
					this.NotifyPropertyChanged("OriginalFileNameWithPath");
				}
			}
		}
	}


What I have tried:

I have tried to change as follows but it does not work.

public static async Task<bool> DisplayOriginalFiles(List<string> files)
Posted
Updated 12-Mar-23 18:06pm
Comments
Graeme_Grant 13-Mar-23 0:00am    
moved

1 solution

Why this code? It won't help unless you have thousands of files. There is a cost to marshall methods to a remote thread and back. Every change to the ObservableCollection must happen on the UI thread.

If you do have thousands of files, then you would need to batch changes and then add to the ObservableCollection with the batch rather than individually. The optimal solution is to roll your own ObservableCollection that does not trigger a CollectionChanged event for each individual change. Here is an example of how to do this: GitHub - ENikS/ObservableCollectionEx[^]

The cheap and nasty way to make synchronous run in a thread using TPL is to use Task.Run Method (System.Threading.Tasks) | Microsoft Learn[^].

As mentioned above, you may be running on a seperate thread to the UI. So you will need to marshall back to the UI thread to update the ObservableCollection as it is not thread-safe. Here is a helper class:
C#
namespace System.Windows.Threading;

public static class DispatcherHelper
{
    public static void Execute(Action action)
    {
        if (Application.Current is null || Application.Current.Dispatcher is null)
            return;

        // Marshall to Main Thread
        Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Background, action);
    }
}

To use, from the remote thread where your code is running and want to update the ObservableCollection, you would use it like this:
C#
DispatcherHelper.Execute(() => MyCollection.Add(DataModel));
 
Share this answer
 
v6

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900