This question already has answers here:
How to deal with cross-thread access exceptions?
(3 answers)
Closed 6 years ago.
getting right to it here is a few lines from the code I have in my code behind:
private static Factual factual = new Factual(FACTUAL_KEY, FACTUAL_SECRET);
private void OnStartQueries_Click(object sender, RoutedEventArgs e)
{
RunAsyncQuery(43.0120, -81.2003, 3000, 25).ContinueWith(task => rtbJsonData.AppendText(task.Result));
}
private static async Task<string> RunAsyncQuery(double lat, double lng, int radius, int limit)
{
return await Task.Run(() => factual.Fetch("places", new Query().WithIn(new Circle(lat, lng, radius)).Limit(limit)));
}
So as you can see when I click the Start Queries button I want to run a method asynchronously. When it returns with the result from that query, I want to set the text of the RichTextBox "rtbJsonData" to the result. However, currently when I run it I get the exception:
"The calling thread cannot access this object because a different thread owns it."
How can I do this?
The RichTextBox "rtbJsonData" is being owned by the main thread and cannot be accessed from another thread directly.
In WPF, your model can you can derive from the INotifyPropertyChanged interface. Any changes on the model will be updated on the view.
See MSDN for a full example: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx
This is based on the MVVM (Model View View-Model) pattern, https://msdn.microsoft.com/en-us/library/hh848246.aspx
Related
This question already has answers here:
How do I update the GUI from another thread?
(47 answers)
Closed 1 year ago.
Good morning everyone, I'm having trouble with rewriting a DataGrid, the function works, but I would need to do a faster search, so the thought was to add parallelism.
But upon applying the latter it generates an error for me: System.InvalidOperationException: 'Invalid cross-thread operation: the control 'dataGridView1' was accessed from a different thread than the one from which the creation was performed.'
The problem is clear to me, however I can't figure out how to solve it. Could you guys please help me out?
I've already tried applying Invoke but the program goes into an infinite loop.
private void inputSearch_TextChanged(object sender, EventArgs e)
{
Parallel.For(0, 7, i =>
{
Ricerca(i);
});
}
private void Ricerca(int i)
{
string searchValue = inputSearch.Text.ToUpper();
var re = from row in dataTable.AsEnumerable()
where
row[i].ToString().Contains(searchValue)
select row;
if (re.Count() != 0)
{
Invoke(new Action(() =>
{
dataGridView1.DataSource = re.CopyToDataTable();
dataGridView1.Columns[7].Visible = false;
}));
}
}
You have a deadlock because you are blocking the UI thread in inputSearch_TextChanged method (that is invoked by UI thread).
If your intent is to parallelize the Linq expression, split Ricerca method in two. The final part of the method should be invoked out of the parallel for, maybe directly on inputSearch_TextChanged.
A better solution could be to use .NET Task instead.
Otherwise, if you don't need parallel at all, you can replace it with a simple for.
I was able to solve the problem as suggested by Cherry by saving the content in another table and recopying it later.
private void inputSearch_TextChanged(object sender, EventArgs e)
{
Parallel.For(0, 7, i =>
{
Ricerca(i);
});
dataGridView1.DataSource = table;
dataGridView1.Columns[7].Visible = false;
}
private void Ricerca(int i)
{
string searchValue = inputSearch.Text.ToUpper();
var re = from row in dataTable.AsEnumerable()
where
row[i].ToString().Contains(searchValue)
select row;
if (re.Count() != 0)
{
table = re.CopyToDataTable();
}
}
Thanks to all!
This question already has answers here:
Accessing UI (Main) Thread safely in WPF
(3 answers)
Closed 8 years ago.
why this code wont work without Dispatcher.RunAsync and what does it do? without Dispatcher its throwing error at copying value to textv.Text " thats its on different thread"
async void Current_GeofenceStateChanged(GeofenceMonitor sender, object args)
{
var reports = sender.ReadReports();
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
foreach (var report in reports)
{
GeofenceState st = report.NewState;
Geofence gf2 = report.Geofence;
if (st == GeofenceState.Entered)
{
textv2.Text = "Hello"; //XAML TEXT
}
else if(st==GeofenceState.Exited)
{
textv2.Text = "Bye";
}
}
});
}
The Event Current_GeofenceStateChanged is being fired outside of the GUI thread and only the GUI thread can change GUI elements. Dispatcher.RunAsync says the code inside should run on the GUI thread so it works.
if you put the result on a string variable it will work if you only put:
Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => textv2.Text = StringVariable;);
EDIT: I only noticed that you have XAML code later you can just put the string on a property and bind the property to the text value of the text box letting you free from the Dispatcher.
<TextBox Text="{Binding StringVariable}"/>
and on the code just have
public string StringVariable { get; set; }
than on the method just set the value to the property
StringVariable = "bla bla";
This question already has an answer here:
How to correctly implement a BackgroundWorker with ProgressBar updates?
(1 answer)
Closed 8 years ago.
I have a .cab extraction utility. On my main window, I want to show the name of .cab being extracted, which file is being extracted right now, and the percentage of extraction done.
I have written properties for each field i.e. file name, percentage, etc... which are on my ViewModel.
All is working fine but it is not reflected on UI
MainVindowViewModel:
public string FileExtract
{
get
{
return _fileExtract;
}
set
{
_fileExtract = value;
NotifyPropertyChanged("FileExtract");
}
}
public int Percent
{
get
{
return _percent;
}
set
{
_percent = value;
NotifyPropertyChanged("Percent");
}
}
Method for extraction
private void ExtractCab(string outputDirectory)
{
m_CabinetFile.FileExtractBefore += new EventHandler(CabinetFile_FileExtractBefore);
m_CabinetFile.FileExtractComplete += new EventHandler(CabinetFile_FileExtractComplete);
}
above two events triggers before and after file is extracted respectively.
With the following methods I get all info that I required when cab is getting extracted, but it is not reflected on UI
private void CabinetFile_FileExtractBefore(object sender, System.EventArgs e)
{
TFile file = (TFile)sender;
FileExtract = file.FullName;
}
private void CabinetFile_FileExtractComplete(object sender, System.EventArgs e)
{
Count++;
Percent = Convert.ToInt32(((decimal)Count / (decimal)m_CabinetFile.FileCount) * 100);
}
FileExtract and Percent properties are bound to the XAML UI, which is getting updated in code but not in UI. UI is stuck until complete cab has been extracted.
Always use BackgroundWorker to do intensive computations in WPF. Main thread is responsible for UI rendering and if busy with extracting, it cannot respond to other requests.
BackgroudWorker class provides also callbacks to report current progress, which you can use to inform user in UI.
This question already exists:
Multiple Instances New Class() C#
Closed 9 years ago.
I am using the code sample below -
Program.cs has a list of clients as:
public static List<Client> clients = new List<Client>();
with an event handler for click on button1
private void button1_Click(object sender, EventArgs e)
{
Client client = new Client(combobox1.selecteditem);
Program.clients.Add(client);
}
Client.cs
All variables are non-static and public. There is an eventhandler where on packet receive, a class is called, this class is then filtered and processed
it is called in the following code:
public void recieved(short op, string str, Client c)
{
switch (op)
{
case (short)OpCodes.matches:
{
c.something(c, str);
break;
}
}
}
Handler.cs
public void something(Client c, string movement)
{
if (movement == null)
c.coords = movement;
c.freeSpot = true;
}
And in the above ^ the variables would overlap and freespot would be made true throughout all the instances.
It will work fine with one instance. But I'm trying to compile with multiple instances.
So creating a button_onclick would create a new instance using the above.
As the program is running, it runs flawlessly on one instance, but with 2+ instances, the variables in MyClass start to overlap. Is there a way to prevent this?
I can't say for certain without more context, but this may be a concurrency problem. List is not thread safe. Try using ConcurrentBag<T> instead of List<T>.
Got some problem and cant't get why it appears.
I'm using .net 4.5 / C# and I try to set Content to a ContentControl after an async function succeeded.
The main focus of what i want to to in that part of the programm is to switch between an own WPF Loading animation (Usercontrol IsLoading) and a PDF Content (Usercontrol PDFDokument). The PDF is internal loaded & rendered inside the "PDFDokument" and works already very well.
If more information is needed, every asking is welcome.
For you to know i would say i'm still at a beginning level of developing. (the first of three years :) )
public ucPDFDocument PDFDokument = new ucPDFDocument();
public ucLoading IsLoading = new ucLoading();
protected async void lstSuchergebnis_DoubleClickItem(object sender, MouseButtonEventArgs e)
{
var tempAkte = ((ListViewItem)sender).Content as Akten;
tbctrlResultPanel.SelectedIndex = 1;
PDFDokument.IsDataChangeAllowed(false);
contSwapControls.Content = IsLoading;
await PDF(tempAkte);
contSwapControls.Content = PDFDokument; **<-- after executing this line, the ui freezes**
}
private Task PDF(Akten paramAkte)
{
Akten _tempAkte = paramAkte;
return Task.Run(() => { PDFDokument.LoadPDFDokument(_tempAkte.akt_ID, ref _DaKsManger); });
}
I tried different ways of using that async loading, but nothing solved that problem.
Hope someone got an idea how to solve that :)
Thanks a lot!!!
The only thing that is async is PDF(...), which you await. Setting the content is not being executed in an async manner. The content you are setting happens on the UI thread. (which is the only way to do so, since you are modifying the UI, which can only happen on the thread it is created on)