Ich habe ein kleines Problem mit dem Laden meiner Daten und Filtern Thread sicher.Bitte helfen Sie mir diesen Code Thread sicher machen
Der folgende Code für die Basisklasse meines Steuerelements, die die gesamte Datenpopulation durch einen BackgroundWorker behandelt. Dies führt dazu, dass der Fehler "this.DataWorker.RunWorkerAsync()" ausgelöst wird, der besagt, dass der BackgroundWorker beschäftigt ist.
/// <summary>
/// Handles the population of the form data.
/// </summary>
/// <param name="reload">Whether to pull data back from the WebService.</param>
public void Populate(bool reload)
{
if (!this.DataWorker.IsBusy)
{
// Disable the filter options
IvdSession.Instance.FilterManager.SetEnabledState(this.GetType(), false);
// Perform the population
this.DataWorker.RunWorkerAsync(reload);
}
else if (!reload)
{
// If the data worker is busy and this is a not reload, then something bad has happened (i.e. the filter has run during a reload.)
throw new InvalidOperationException("The DataWorker was busy whilst asked to reload.");
}
}
Der Code wird in zwei möglichen Orte genannt. Zum einen durch einen Timer auf der Form, dass die Steuerung auf:
auf diepublic void Filter()
{
if (!m_BlockFilter)
{
IvdInstance.Main.CurrentBody.FirstRun = true;
IvdInstance.Main.CurrentBody.Populate(false);
}
}
Der Timer:
private void tmrAutoRefresh_Tick(object sender, EventArgs e)
{
if (!(this.CurrentBody == null))
{
this.CurrentBody.Populate(true);
}
}
Und zweitens, jederzeit ein Benutzer eine Filteroption aus einer Reihe von Dropdown-Listen wählt Das Hauptformular wird alle 60 Sekunden ausgeführt und wird an die Populate-Methode übergeben. Passing reload als trues erzählt die Background, dass es einen neuen Satz von Daten aus dem WebService nach unten ziehen muss:
void dataWorker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
if (base.FirstRun)
{
base.CleanListView();
}
if ((bool)e.Argument)
{
byte[] serialized = IvdSession.DataAccess.GetServiceCalls(IvdSession.Instance.Company.Description, IvdSession.Instance.Company.Password, null);
m_DataCollection = new DalCollection<ServiceCallEntity>(serialized);
}
List<ServiceCallEntity> collection = this.ApplyFilter();
base.HandlePopulation<ServiceCallEntity>(collection, e);
}
catch (WebException ex)
{
// Ignore - Thrown when user clicks cancel
}
catch (System.Web.Services.Protocols.SoapException ex)
{
// Log error on server and stay transparent to user
base.LogError(ex);
}
catch (System.Data.SqlClient.SqlException ex)
{
// Inform user that the database is unavailable
base.HandleSystemUnavailable(ex);
}
}
Soweit ich bin mir dessen bewusst, tritt der Fehler auf, wenn ich es schaffe genau eine Filteroption klicken Gleichzeitig löst der Timer das Populationsereignis aus. Ich denke, es fehlt etwas an der Populate-Methode, d. H. Eine Sperre, aber ich bin nicht sicher, wie ich es in diesem Fall richtig verwenden soll.
Der Code ist gegenüber der Benutzereingabe bevorzugt. Wenn ein Benutzer eine Filteroption auswählt, sollte die automatische Aktualisierung blockiert werden. Wenn die automatische Aktualisierung ausgelöst wird, werden die Filteroptionen vorübergehend deaktiviert. Wenn sie gleichzeitig ausgelöst werden, sollte die Benutzereingabe Vorrang haben (wenn möglich).
Hoffe jemand kann helfen!
@Groo, weiß nicht die genaue Spezifikation von Windows, aber mit Multi-Cores, würden Sie nicht in der Lage sein, zwei Dinge gleichzeitig laufen zu lassen? –
Ja, die Methode * sollte * threadsicher gemacht werden. Aber es gibt eine Regel, dass Sie die Gui-Elemente immer aus dem Gui-Thread aktualisieren müssen. Daher sorgt Windows.Forms.Timer dafür, den Ereignishandler der Gui-Thread-Warteschlange hinzuzufügen (er ruft ihn aus dem Gui-Thread auf), um Dinge zu vereinfachen. – Groo
Hey, wen machst du Witze mit "weiß nicht die genaue Spezifikation von Windows"? :) – Groo