Có thể sử dụng Control.BeginInvoke trong bất kỳ mục đích nào khác ngoài "lửa & quên" cách thức không? Tôi muốn thay đổi yêu cầu sau đây để ủy quyền một phương thức gọi lại để tôi có thể thực hiện điều gì đó khi mỗi cuộc gọi không đồng bộ của tôi hoàn tất.Làm cách nào để ủy quyền một phương thức AsyncCallback cho Control.BeginInvoke? (.NET)
this.BeginInvoke(new RefreshRulesDelegate(RefreshRules), new object[] { ctrl, ctrl.DsRules, ctrl.CptyId });
Tôi có thể làm điều này với đại biểu bình thường.BeginInvoke ví dụ:
RefreshRulesDelegate del = new RefreshRulesDelegate(RefreshRules);
del.BeginInvoke(ctrl, ctrl.DsRules, ctrl.CptyId, new AsyncCallback(RefreshCompleted), del);
Nhưng vì tôi gọi kiểm soát .BeginInvoke tôi không thể làm điều này khi tôi nhận được những "hoạt động cross-đề không hợp lệ" lỗi.
Bất kỳ ai cũng có thể trợ giúp?
Ngoài một số câu trả lời nhận được, tôi sẽ làm rõ "lý do". Tôi cần phải tải/làm mới một điều khiển trên GUI của tôi mà không cần khóa phần còn lại của ứng dụng. Điều khiển chứa nhiều điều khiển (ruleListCtls) mà tất cả đều yêu cầu một tập dữ liệu được lấy ra và truyền cho chúng. tức là
public void RefreshAll()
{
foreach (LTRFundingRuleListControl ctrl in ruleListCtls)
{
this.BeginInvoke(new RefreshRulesDelegate(RefreshRules), new object[]{ctrl,ctrl.DsRules, ctrl.CptyId });
}
}
Tôi đã phát hiện ra rằng tôi có thể làm điều này nếu tôi cung cấp một phương pháp đại biểu gọi lại và di chuyển bất kỳ mã đó sửa đổi các điều khiển trở lại vào thread GUI chính mà chúng được tạo ra (để tránh các lỗi cross-chủ đề)
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;
}
}
Dưới đây là những gì chúng ta delgate đến các chủ đề chính sau khi nhận được gọi lại:
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;
}
}
}
này hiện đang làm việc tốt. Tuy nhiên, vấn đề chính, ngoài ra tôi không nghĩ rằng điều này đặc biệt thanh lịch, là xử lý ngoại lệ. Có lẽ đây là một câu hỏi khác, nhưng nếu RefreshRulesDs ném một ngoại lệ sau đó ứng dụng của tôi bị treo khi lỗi không sôi nổi sao lưu luồng GUI (hiển nhiên) nhưng là một ngoại lệ chưa được xử lý. Cho đến khi tôi có thể bắt được chúng thì tôi sẽ phải thực hiện toàn bộ thao tác này một cách đồng bộ. Làm cách nào để tôi gặp lỗi và tải phần còn lại của các điều khiển của tôi? Hoặc làm cách nào để thực hiện thao tác không đồng bộ này theo cách khác, với xử lý ngoại lệ phù hợp?
Xử lý ngoại lệ hơi lộn xộn, nhưng bạn sẽ có thể bắt chúng bằng EndInvoke xung quanh. BackgroundWorker và Task (Fx 4) làm nó đẹp hơn mặc dù. –