There
I want to disable some rows in objectlistview (Ver. 2.9)
Code:
private void olvPatientstockedOrders_FormatRow(object sender, FormatRowEventArgs e)
{
CServerOrder order = (CServerOrder)e.Model;
if(order.OrderControl.ToUpper().Contains("DC"))
{
olvPatientstockedOrders.DisableObject(e.Model);
}
}
But I get exceptions on code "olvPatientstockedOrders.DisableObject(e.Model);
and there is no details info
DisableObject() internally calls FormatRow (since DisableObject() potentially changes the look/format of the row), so it is stuck in an endless loop and causing a StackOverflowException (like the exception dialog suggests).
Related
tl:dr at the bottom. I am taking a Java course on Udemy and our instructor is demonstrating a situation where background threads can interfere with each other and crash the program. In this case pushing either of the two buttons initiates a method that starts a background Thread, waits, then updates a label. He explains it something along the lines as the threads overwriting each other causing the program to crash with an IllegalStateException. What I don't understand is Threads overwriting each other is not uncommon and just makes the program behave in ways not intended and doesn't usually completely crash the program.
In this case the threads are both trying to change the label to the same String.
Why is this throwing an IllegalStateException instead of just causing the usual interference? After all more than one thread trying to update an object doesn't necessarily crash the program.
tl:dr Why does more than one thread modifying a Label object throw an IllegalStateException in this case but in other multi-threaded programs you just get the usual thread interference? The method of interest is the onButtonClicked() method.
I have tried catching the IllegalStateException to see if I can call Thread.currentThread().getName() but the catch block(both of them actually) seem to get ignored.
public class Controller {
#FXML
private TextField nameField;
#FXML
private Button helloButton;
#FXML
private Button byeButton;
#FXML
private CheckBox ourCheckBox;
#FXML
private Label ourLabel;
#FXML
public void initialize() {
helloButton.setDisable(true);
byeButton.setDisable(true);
}
#FXML
public void onButtonClicked(ActionEvent event) {
if (event.getSource().equals(helloButton)) {
System.out.println("hello, " + nameField.getText());
} else if (event.getSource().equals(byeButton)) {
System.out.println("Bye, " + nameField.getText());
}
Runnable task = new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
ourLabel.setText("We did something");
} catch (InterruptedException e) {
System.out.println("Interuppted Exception " + e.getMessage());
} catch (IllegalStateException e) {
System.out.println("Illegal State Exception: " + e.getMessage() + " "
+ Thread.currentThread().getName());
}
}
};
new Thread(task).start();
if (ourCheckBox.isSelected()) {
nameField.clear();
byeButton.setDisable(true);
helloButton.setDisable(true);
}
}
#FXML
public void handleKeyReleased() {
String text = nameField.getText();
boolean disableButtons = text.isEmpty() || text.trim().isEmpty();
byeButton.setDisable(disableButtons);
helloButton.setDisable(disableButtons);
}
#FXML
public void handleChange() {
System.out.println("The checkbox is " +
(ourCheckBox.isSelected() ? "checked" : "not checked"));
}
}
Updating active scene graph elements (such as label text) in your own threads has the potential to cause a race condition (please read and understand the Software section of the link) in the internal state of the JavaFX system. The results of which are unpredictable and a corruption or ”crash” of the JavaFX system cannot be ruled out. Perhaps nothing bad will happen, but perhaps something bad will.
Some calls to JavaFX APIs will detect when potential race condition may occur (when they are being invoked by a thread which is not the JavaFX thread), and fail fast by throwing an IllegalStateException. Other JavaFX APIs may not bother to check the calling thread and may not throw an IllegalStateException, thus allowing the potential race condition to occur. Either way, the users calling code is wrong, it should not be trying to modify the active scene graph off of the JavaFX application thread.
JavaFX code which manipulates the active scene graph (elements or properties of elements currently being displayed in a rendered scene) is only ever expected to occur on a single thread (the JavaFX application thread). In that way a race condition cannot occur.
If you want to feedback information from another thread to the UI, then you can either use the Platform.runLater API, which will execute a piece of code at some time in the future on the JavaFX thread, or make use of utilities in the javafx.concurrent package.
I have method
public override void InitializeRow(object sender, InitializeRowEventArgs e)
{
if (!e.ReInitialize)
Task.Factory.StartNew(() =>
{
AfterInitializeRow(sender, e);
});
}
public override void AfterInitializeRow(object sender, InitializeRowEventArgs e)
{
foreach (UltraGridColumn ugc in e.Row.Band.Columns)
{
if (IsNumeric(ugc.Key))
{
e.Row.Cells[ugc].DroppedDown = true;
e.Row.Cells[ugc].ValueList = “Some value”;
e.Row.Cells[ugc].SetValue(e.Row.Cells[ugc.Key].Value, false);
e.Row.Cells[ugc].Style = Infragistics.Win.UltraWinGrid.ColumnStyle.DropDownList;
}
}
}
But its Giving error at e.Row.Cells[ugc].DroppedDown = true;
I learned that only Main thread can update the UI.
But is it possible that while updating the DroppedDown only it switch to main thread. Bcoz more than 1000’s rows are initialized in this way making the load of Grid very slow. So I want to do some kind of parallelism in this process.
In any function in your Form or UserControl, you can use the following type of code:
public void SetText(string text)
{
if (InvokeRequired)
{
BeginInvoke(new Action<string>(SetText), text);
}
else
{
label1.Text = text;
}
}
label1 would be the control to update in this case.
This will make sure that you invoke the function on the UI-thread.
You should still be careful with syncrhonization, though, but simply updating your UI from another thread can be easily done like that.
The answer to this question is that you shouldn't be using threading in the InitialzieRow event to set or even access properties on the grid or its related objects.
What you should do instead is look for ways to optimize what you are doing in this method first. For example why are you setting the value of a cell to the value it already has, this line of code should be able to be removed without impacting behavior.
Also all of the logic provided is only based on the column key so if the column has a consistent set of values, you could set the ValueList on the column in InitializeLayout instead of using InitializeRow.
I am beginner to C# .net. I have simple app in wpf which access a listbox from user thread. in winforms i can use invokerequired, a equivalent for wpf using dispatcher did not help. My system also hangs for the buttons so debugging is though. Please provide solution for the below code. thanks in advance
private void Monitor_mtd()
{
while (AppStatus != 0)
{
if (flag2 == 1)
{
listBox1.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new list1MtdDelegate(list1Mtd), "Best practice");
}
}
}
private delegate void list1MtdDelegate(string ls1);
private void list1Mtd(string ls1)
{
listBox1.Items.Add(ls1);
}
private void button1_Click_1(object sender, RoutedEventArgs e)
{
Monitor = new Thread(new ThreadStart(Monitor_mtd));
Monitor.Start();
flag1 = 1;
}
private void button2_Click(object sender, RoutedEventArgs e)
{
flag2 = 1;
}
There are a couple of issues that arise in your approach. Firstly, the way that you bind your data to the ListBox and secondly trying to update the ListBox from a user thread.
You can solve the binding of the ListBox by using an ObservableCollection so that the UI is updated with the necessary values (have a look at this post for more information on this). However, this also raises another problem and that is that the ObservableCollection cannot be called from another thread other than the one it is dispatching (see more on this here also). This means that you need another implementation for the ObservableCollection. Thomas Levesque made an AsyncObservableCollection that can be modified from any thread and still notify the UI when its modified.
I made a sample implementation that you can download here showing the full solution.
I have 2 Telerik's rad grids. First one is master and second one is detail. I can delete rows from both grids independently by pressing "Delete" button on toolbar above each grid. I also have "Refresh" buttons in toolbar of both grids.
The problem is with detail grid. When I delete item(s) the grid doesn't refresh. Calling Rebind method doesn't help. The only thing that helps is to press "Refresh" button in toolbar of master grid and select the row in master grid by mouse that was previously selected. After that I can see refreshed detail grid.
So, I don't need to press "Refresh" button in toolbar of master grid and select the row in master grid by mouse. I can refresh the master grid programmatically and only want to reselect the item that was originally selected also programmatically. I've tried this:
item.Selected = true;
But, it only visually selects the item in master grid and doesn't refresh the detail grid.
So, how to select the item in master grid programmatically in order to get the same effect as selecting it by mouse?
Thank you in advance.
I've just realised that your probably using different DataSource for both grids, but pointing to the same database, right? My example below uses the same datasource for both grids. However I made on a detail view versus a normal view by making some columns not visible. Maybe this strategy could fix your issue?
My first thought was to try implement the SelectionChanged event, or if not that, the SelectionChanging event. Put a refresh in there you see. But I didn't end up doing it that way.
I wrote a small program as below. It saves the edits to disk with any row change as long as its not a remove (I had trouble saving remove edits when the button was clicked it gave a null pointer exception on the remove command). It also saves changes just before closing the program (so that any delete rows are also saved then). I did find that the deleteOne and deleteTwo buttons (that delete from the first or second grid, respectively) do in fact cause the deletion to occur in both grids. So a possibility is you could use the radGridView1.Rows.Remove(row) or RemoveAt(i) command if that works in your situation?
Another possibility is that if refresh isn't working you could set the DataSource to null and then set it to the data source again, after deleting the row. This is a bit drastic but if it's the only thing that works? I'm talking about the data source for both grids.
My code is below:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Telerik.WinControls;
using Telerik.WinControls.Data;
using Telerik.WinControls.UI;
namespace RadControlsWinFormsApp1
{
public partial class RadForm1 : Telerik.WinControls.UI.RadForm
{
public RadForm1()
{
InitializeComponent();
}
private void RadForm1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'testdbDataSet.Customers' table. You can move, or remove it, as needed.
this.customersTableAdapter.Fill(this.testdbDataSet.Customers);
radGridView1.Columns["Address"].IsVisible = false;
}
private void radGridView1_RowsChanged(object sender, Telerik.WinControls.UI.GridViewCollectionChangedEventArgs e)
{
// if removing don't update, because if my delete button is pressed this
// will otherwise cause all sorts of problems and freezes the grid
if (e.Action != NotifyCollectionChangedAction.Remove)
{
try
{
customersTableAdapter.Update(testdbDataSet);
}
catch (DBConcurrencyException ex)
{
// unable to save right now, don't worry about it
}
}
radGridView2.Refresh();
}
private void butDeleteOne_Click(object sender, EventArgs e)
{
bool haveRemoved = false;
for (int i = 0; i < radGridView1.Rows.Count && !haveRemoved; ++i)
{
GridViewRowInfo row = radGridView1.Rows[i];
if (row.IsSelected)
{
haveRemoved = true;
radGridView1.Rows.RemoveAt(i);
}
}
}
private void butDeleteTwo_Click(object sender, EventArgs e)
{
bool haveRemoved = false;
for (int i = 0; i < radGridView2.Rows.Count && !haveRemoved; ++i)
{
GridViewRowInfo row = radGridView2.Rows[i];
if (row.IsSelected)
{
haveRemoved = true;
radGridView2.Rows.RemoveAt(i);
}
}
}
private void radGridView2_RowsChanged(object sender, GridViewCollectionChangedEventArgs e)
{
// if removing don't update, because if my delete button is pressed this
// will otherwise cause all sorts of problems and freezes the grid
if (e.Action != NotifyCollectionChangedAction.Remove)
{
try
{
customersTableAdapter.Update(testdbDataSet);
}
catch (DBConcurrencyException ex)
{
// unable to save right now, don't worry about it
}
}
radGridView1.Refresh();
}
private void RadForm1_FormClosing(object sender, FormClosingEventArgs e)
{
// ensure all data is saved back into database on close
customersTableAdapter.Update(testdbDataSet);
}
//private void radGridView1_CellEndEdit(object sender, Telerik.WinControls.UI.GridViewCellEventArgs e)
//{
//}
}
}
I'm testing my app with mono in prevision of a Linux port, and I have a threading problem. I initially considered pasting 3000 code lines here, but finally I've devised a small minimal example ;)
You have a form with a button (poetically named Button1, and a label (which bears, without surprise, the name Label1)). The whole lot is living a happy life on a form called Form1. Clicking Button1 launches an infinite loop that increments a local counter and updates Label1 (using Invoke) to reflect its value.
Now in Mono, if you resize the form, the label stops updating, never to restart. This doesn't happen with MS implementation. BeginInvoke doesn't work any better; worse, it makes the UI hang in both cases.
Do you know where this discrepancy comes from? How would you solve it? And finally, why doesn't BeginInvoke work here? I must be making a huge mistake... but which?
EDIT:
Some progress so far:
Calling BeginInvoke does in fact work; only, the UI just doesn't refresh fast enough, so it seems to stop.
On mono, what happens is that the whole thread hangs when you insert a message in the UI queue (eg by resizing the form). In fact, the synchronous Invoke call never returns. I'm trying to understand why.
Of interest: even using BeginInvoke, the asynchronous calls don't get executed before the resizing operation ends. On MS.Net, they keep running while resizing.
The code looks like this (C# version lower):
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim T As New Threading.Thread(AddressOf Increment)
T.Start()
End Sub
Sub UpdateLabel(ByVal Text As String)
Label1.Text = Text
End Sub
Delegate Sub UpdateLabelHandler(ByVal Text As String)
Sub Increment()
Dim i As Long = 0
Dim UpdateLabelDelegate As New UpdateLabelHandler(AddressOf UpdateLabel)
Try
While True
i = (i + 1) Mod (Long.MaxValue - 1)
Me.Invoke(UpdateLabelDelegate, New Object() {i.ToString})
End While
Catch Ex As ObjectDisposedException
End Try
End Sub
End Class
Or, in C#,
public class Form1
{
private void Button1_Click(System.Object sender, System.EventArgs e)
{
System.Threading.Thread T = new System.Threading.Thread(Increment);
T.Start();
}
public void UpdateLabel(string Text)
{
Label1.Text = Text;
}
public delegate void UpdateLabelHandler(string Text);
public void Increment()
{
long i = 0;
UpdateLabelHandler UpdateLabelDelegate = new UpdateLabelHandler(UpdateLabel);
try {
while (true) {
i = (i + 1) % (long.MaxValue - 1);
this.Invoke(UpdateLabelDelegate, new object[] { i.ToString() });
}
} catch (ObjectDisposedException Ex) {
}
}
}
This is a bug in the mono runtime, at least I think it is. The code might not be good practice (I'm not a threading expert), but the thing that suggests a bug is the fact that the behaviour differs on windows and Linux.
On Linux, mono has exactly the same behaviour as MS.Net has on windows. No hanging, continuous updates even while resizing.
On Windows, mono displays all the aforementioned problems. I've posted a bug report at https://bugzilla.novell.com/show_bug.cgi?id=690400 .
Do you know where this discrepancy
comes from? How would you solve it?
I am not sure. I do not see anything obvious in your code that would cause the difference between Mono and .NET. If I had to make a wild guess I would say there is a possibility that you have stumbled upon an obscure bug in Mono. Though, I suppose it is possible that Mono uses a sufficiently different mechanism for handling the WM_PAINT messages that cause the form to get refreshed. The constant pounding of the UI thread from repeated calls to Invoke may be disrupting Mono's ability to get the form refreshed.
And finally, why doesn't BeginInvoke
work here?
Calling Invoke in a tight loop is bad enough, but BeginInvoke will be even worse. The worker thread is flooding the UI message pump. BeginInvoke does not wait until the UI thread has finished executing the delegate. It just posts the requests and returns quickly. That is why it appears to hang. The messages that BeginInvoke is posting to the UI message queue keep building up as the worker thread is likely severely out pacing the UI thread's ability to process them.
Other Comments
I should also mention that the worker thread is nearly useless in the code. The reason is because you have a call to Invoke on every iteration. Invoke blocks until the UI has finished executing the delegate. That means your worker thread and UI thread are essentially in lock-step with each other. In other words, the worker is spending most of its time waiting for the UI and vice versa.
Solution
One possible fix is to slow down the rate at which Invoke is called. Instead of calling it on every loop iteration try doing it every 1000 iterations or the like.
Any even better approach is to not use Invoke or BeginInvoke at all. Personally, I think these mechanisms for updating the UI are way overused. It is almost always better to let the UI thread throttle its own update rate especially when the worker thread is doing continuous processing. This means you will need to place a timer on the form and have it tick at the desired refresh rate. From the Tick event you will probe a shared data structure that the worker thread is updating and use that information to update the controls on the form. This has several advantages.
It breaks the tight coupling between the UI and worker threads that Control.Invoke imposes.
It puts the responsibility of updating the UI thread on the UI thread where it should belong anyway.
The UI thread gets to dictate when and how often the update should take place.
There is no risk of the UI message pump being overrun as would be the case with the marshaling techniques initiated by the worker thread.
The worker thread does not have to wait for an acknowledgement that the update was performed before proceeding with its next steps (ie. you get more throughput on both the UI and worker threads).
First and foremost: clicking on Button1 is asynchronous already, so you don't need to create another thread to increment, just call the increment method Sorry, I was reading your question line by line and by the time I got to the while-loop I forgot about the button:
private void Button1_Click(System.Object sender, System.EventArgs e)
{
Thread t = new Thread(Increment);
t.IsBackground = true;
t.Start();
}
Second: if you do need to use a thread then you should always set your thread to background (i.e. foreground prevents your process from terminating), unless you have a good reason for using a foreground thread.
Third: if you're making updates to the UI, then you should check the InvokeRequired property and call BeginInvoke:
public void UpdateLabel(string Text)
{
if (InvokeRequired)
{
BeginInvoke(new UpdateLabelDelegate(UpdateLabel), Text);
}
else
{
Label1.Text = Text;
}
}
public void Increment()
{
int i = 0;
while(true)
{
i++; // just incrementing i??
UpdateLabel(i.ToString());
Thread.Sleep(1000);// slow down a bit so you can see the updates
}
}
You can also "automate" the Invoke Required "pattern": Automating the InvokeRequired code pattern
And now see if you're still having the same problem.
I tried it on my machine and it works like a charm:
public partial class Form1 : Form
{
private delegate void UpdateLabelDelegate(string text);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(Increment);
t.IsBackground = true;
t.Start();
}
private void UpdateLabel(string text)
{
if (label1.InvokeRequired)
{
BeginInvoke(new UpdateLabelDelegate(UpdateLabel), text);
}
else
{
label1.Text = text;
}
}
private void Increment()
{
int i = 0;
while (true)
{
i++;
UpdateLabel(i.ToString());
Thread.Sleep(1000);
}
}
}