Ist es möglich, Control.BeginInvoke in einem anderen als einem "Feuer & vergessen" Weise zu verwenden? Ich möchte die folgende Anfrage ändern, um eine Rückrufmethode zu delegieren, so dass ich etwas tun kann, wenn jeder meiner asynchronen Anrufe abgeschlossen ist.Wie delegiere ich eine AsyncCallback-Methode für Control.BeginInvoke? (.NET)
this.BeginInvoke(new RefreshRulesDelegate(RefreshRules), new object[] { ctrl, ctrl.DsRules, ctrl.CptyId });
Ich wäre in der Lage, dies mit einem normalen delegate.BeginInvoke z.
RefreshRulesDelegate del = new RefreshRulesDelegate(RefreshRules);
del.BeginInvoke(ctrl, ctrl.DsRules, ctrl.CptyId, new AsyncCallback(RefreshCompleted), del);
Aber weil ich Kontrolle .BeginInvoke bin Aufruf Ich kann das nicht tun, wie ich den „Cross-Thread-Betrieb ungültig“ Fehler.
Wer hilft?
Weiter zu einigen der Antworten erhalten, werde ich das "warum" klären. Ich muss ein Control auf meiner GUI laden/aktualisieren, ohne den Rest der App zu sperren. Das Steuerelement enthält zahlreiche Steuerelemente (ruleListCtls), die erfordern, dass ein Dataset abgerufen und an sie übergeben wird. dh
public void RefreshAll()
{
foreach (LTRFundingRuleListControl ctrl in ruleListCtls)
{
this.BeginInvoke(new RefreshRulesDelegate(RefreshRules), new object[]{ctrl,ctrl.DsRules, ctrl.CptyId });
}
}
Ich habe festgestellt, daß ich dies tun kann, wenn ich einen Delegierten Callback-Methode zur Verfügung stellen und einen Code bewegen, die die Kontrollen zurück auf die Haupt GUI-Thread ändert, auf dem sie erzeugt wurden (die Querfadenfehler zu vermeiden,)
public void RefreshAll()
{
IntPtr handle;
foreach (LTRFundingRuleListControl ctrl in ruleListCtls)
{
handle = ctrl.Handle;
RefreshRulesDsDelegate del = new RefreshRulesDsDelegate(RefreshRulesDs);
del.BeginInvoke(ctrl.DsRules, ctrl.CptyId, handle, out handle, new AsyncCallback(RefreshCompleted), del);
}
}
private void RefreshCompleted(IAsyncResult result)
{
CptyCatRuleDataSet dsRules;
string cptyId;
IntPtr handle;
AsyncResult res = (AsyncResult) result;
// Get the handle of the control to update, and the dataset to update it with
RefreshRulesDsDelegate del = (RefreshRulesDsDelegate) res.AsyncDelegate;
dsRules = del.EndInvoke(out handle,res);
// Update the control on the thread it was created on
this.BeginInvoke(new UpdateControlDatasetDelegate(UpdateControlDataset), new object[] {dsRules, handle});
}
public delegate CptyCatRuleDataSet RefreshRulesDsDelegate(CptyCatRuleDataSet dsRules, string cptyId, IntPtr ctrlId, out IntPtr handle);
private CptyCatRuleDataSet RefreshRulesDs(CptyCatRuleDataSet dsRules, string ruleCptyId, IntPtr ctrlId, out IntPtr handle)
{
try
{
handle = ctrlId;
int catId = ((CptyCatRuleDataSet.PSLTR_RULE_CAT_CPTY_SelRow)dsRules.PSLTR_RULE_CAT_CPTY_Sel.Rows[0]).RULE_CAT_ID;
return ltrCptyRulesService.GetCptyRules(ruleCptyId, catId);
}
catch (Exception ex)
{
throw ex;
}
}
Hier ist, was wir auf der Haupt-Thread delgate den Rückruf erhalten zu haben:
private delegate void UpdateControlDatasetDelegate(CptyCatRuleDataSet dsRules, IntPtr ctrlId);
private void UpdateControlDataset(CptyCatRuleDataSet dsRules, IntPtr ctrlId)
{
IEnumerator en = ruleListCtls.GetEnumerator();
while (en.MoveNext())
{
LTRFundingRuleListControl ctrl = en.Current as LTRFundingRuleListControl;
if (ctrl.Handle == ctrlId)
{
ctrl.DsRules = dsRules;
}
}
}
funktioniert gut Dieses jetzt. Das Hauptproblem, abgesehen davon, dass das nicht besonders elegant ist, ist das Ausnahme-Handling. Vielleicht ist das eine andere Frage, aber wenn RefreshRulesDs eine Ausnahme auslöst, stürzt meine App ab, da der Fehler nicht in den GUI-Thread zurückgeblasen wird (offensichtlich), sondern als unbehandelte Ausnahme. Bis ich diese fangen kann, muss ich diese ganze Operation synchron machen. Wie kann ich einen Fehler erfolgreich erfassen und den Rest meiner Steuerelemente laden? Oder wie erreiche ich diese asynchrone Operation auf eine andere Art und Weise, mit der richtigen Ausnahmebehandlung?
Die Ausnahmebehandlung ist ein bisschen unordentlich, aber Sie sollten in der Lage sein, sie durch umgebende EndInvoke zu fangen. BackgroundWorker und Task (Fx 4) machen es aber netter. –