gpt4 book ai didi

c# - 从任务工厂调度的线程更新 WPF 中的 UI 的正确方法是什么?

转载 作者:行者123 更新时间:2023-12-03 13:20:38 25 4
gpt4 key购买 nike

我正在尝试从通过 Task.Factory 调度的线程之一更新 UI .我很难正确更新我的 UI。

这是我观察到的行为:

Task.Factory.StartNew(() =>
{
// UI does get updated from here.
}).ContinueWith(task =>
{
// UI does *not* get updated from here.
});

Task Factory 调度的线程中更新 UI 的正确方法是什么? ?

这是我的实际代码供您引用:
private string CurrentProcess
{
set { _eventAggregator.GetEvent<CurrentProcessUpdatedEvent>().Publish(value); }
}

private double ProgressPercentage
{
set
{
_eventAggregator.GetEvent<ProgressPercentageUpdatedEvent>()
.Publish(Utilities.GetProgressPercentage(value));
}
}
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var tasks = new List<Task<DataTable>>();

string siteCollectionUrl;
string connectionString;

try
{
Dictionary<string, object> session = ApplicationContext.Current.Session;

try
{
if ((double) session["ProgressPercentage"] > 0) return;
}
catch
{
}

siteCollectionUrl = (string) session["SiteCollection"];
connectionString = (string) session["Database"];
}
catch
{
return;
}

_eventAggregator.GetEvent<IsProcessingChangedEvent>().Publish(true);
CurrentProcess = "Loading resources.";

Task<DataTable> spTask = Task<DataTable>.Factory.StartNew(() =>
{
using (ChannelFactory<ISharePointService> service = Utilities.GetSharePointService())
{
ISharePointService sharePointService = service.CreateChannel();
DataTable spDatatable = sharePointService.GetResources(siteCollectionUrl);

Task.Factory.StartNew(() => { ProgressPercentage = 10; }, CancellationToken.None, TaskCreationOptions.None, uiScheduler);

return spDatatable;
}
});

tasks.Add(spTask);

Task<DataTable> buildTableTask = Task<DataTable>.Factory.ContinueWhenAll(tasks.ToArray(), t =>
{
DataTable spDatatable = t[0].Result;

double percent = 10/spDatatable.Rows.Count;

var columnMap = new Dictionary<string, string>
{
{"IsValid", null},
{"Reason", null},
{"SPID", "ID"},
{"DBID", "EXTID"},
{"Name", "Title"},
{"Account", "SharePointAccount"},
{"Email", "Email"},
{"Generic", "Generic"},
{"Department", "Department"},
{"TempDept", "TempDept"},
{"Role", "Role"},
{"TempRole", "TempRole"},
{"HolidaySchedule", "HolidaySchedule"},
{"WorkHours", "WorkHours"}
};

DataTable spResources = BuildDataTable(columnMap);

foreach (DataRow dataRow in spDatatable.Rows)
{
DataRow row = spResources.NewRow();

foreach (var pair in columnMap)
{
try
{
row[pair.Key] = dataRow[pair.Value];
}
catch
{
}
}

spResources.Rows.Add(row);

Task.Factory.StartNew(() => { ProgressPercentage = percent; }, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
}

return spResources;
});

tasks.Add(buildTableTask);

Task<DataTable> dbTask = Task<DataTable>.Factory.StartNew(() =>
{
using (var sqlConnection = new SqlConnection(connectionString))
{
using (var sqlCommand = new SqlCommand(SQL, sqlConnection))
{
sqlConnection.Open();
using (SqlDataReader sqlDataReader = sqlCommand.ExecuteReader())
{
var dataTable = new DataTable();
dataTable.Load(sqlDataReader);

Task.Factory.StartNew(() => { ProgressPercentage = 10; }, CancellationToken.None, TaskCreationOptions.None, uiScheduler);

return dataTable;
}
}
}
});

tasks.Add(dbTask);

Task.Factory.ContinueWhenAll(tasks.ToArray(), t =>
{
DatabaseResources = t[2].Result;
DataTable sharePointResources = t[1].Result;

if (sharePointResources != null)
{
int resourceIndex = 1;
int totalResources = sharePointResources.Rows.Count;
double percentPoint = 70/totalResources;

foreach (DataRow row in sharePointResources.Rows)
{
DataRow currentRow = row;

Task.Factory.StartNew(() =>
{
CurrentProcess = string.Format("[{0}/{1}] Processing: {2}",
resourceIndex++, totalResources,
currentRow["Name"]);
}, CancellationToken.None, TaskCreationOptions.None, uiScheduler);

bool isValid = true;
var reasons = new List<string>();

DataRow[] dataRows =
_databaseResources.Select(string.Format("ResourceID = {0}", row["DBID"]));
if (dataRows.Any())
{
DataRow dataRow = dataRows[0];

string tempDept = (row["TempDept"] ?? string.Empty).ToString();
string dept = (row["Department"] ?? string.Empty).ToString();

string tempRole = (row["TempRole"] ?? string.Empty).ToString();
string role = (row["Role"] ?? string.Empty).ToString();

string hs = (row["HolidaySchedule"] ?? string.Empty).ToString();
string dbhs = (dataRow["HolidaySchedule"] ?? string.Empty).ToString();

string wh = (row["WorkHours"] ?? string.Empty).ToString();
string dbwh = (dataRow["WorkHours"] ?? string.Empty).ToString();

if (string.IsNullOrEmpty(dept))
{
if (!dept.Equals(tempDept))
{
isValid = false;
reasons.Add("Department does not match Temp Dept");
}
}

if (string.IsNullOrEmpty(role))
{
if (!role.Equals(tempRole))
{
isValid = false;
reasons.Add("Role does not match Temp Role");
}
}

if (string.IsNullOrEmpty(hs))
{
if (!hs.Equals(dbhs))
{
isValid = false;
reasons.Add("Holiday Schedule does not match Holiday Schedule from database");
}
}

if (string.IsNullOrEmpty(wh))
{
if (!wh.Equals(dbwh))
{
isValid = false;
reasons.Add("Work Hours does not match Work Hours from database");
}
}
}
else
{
isValid = false;
reasons.Add("Resource does not exist in database");
}

row["IsValid"] = isValid;
row["Reason"] = string.Join("\n", reasons.ToArray());

Task.Factory.StartNew(() => { ProgressPercentage = percentPoint; }, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
}

SharePointResources = sharePointResources;
}

_eventAggregator.GetEvent<ProgressPercentageUpdatedEvent>()
.Publish(Utilities.ResetProgressPercentage());
_eventAggregator.GetEvent<IsProcessingChangedEvent>().Publish(false);
});

最佳答案

// UI does get updated from here



您应该启动 new Action(() =>通过 DispatcherObject在 WPF 中
Task.Factory.StartNew(() =>
    {
        // UI does get updated from here
this.Dispatcher.BeginInvoke(new Action(() =>
{

请搜索 Alexandra Rusina 的系列“.NET Framework 4 中的并行编程”的“ Part 1 - Getting Started”中的最后一行

我相信你会进一步享受这个引用的所有续集。

Part 2- Task Cancellation演示如何改用任务调度程序:
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.ContinueWhenAll(tasks.ToArray(),
result =>
{
var time = watch.ElapsedMilliseconds;
label1.Content += time.ToString();
}, CancellationToken.None, TaskContinuationOptions.None, ui);

代替:
Task.Factory.ContinueWhenAll(tasks.ToArray(),
result =>
{
var time = watch.ElapsedMilliseconds;
this.Dispatcher.BeginInvoke(new Action(() =>
label1.Content += time.ToString()));
});

回应评论

"First of all, I am using PRISM. So, in my ViewModwl I have to use Dispatcher.Current.BeginInvoke --- I tried that. It did not help"



请查看 "Is WPF Dispatcher the solution of multi threading problems?" 的答案与在 Prism 中使用调度程序和访问 UI 相关:
// Not a UI component
public class MyDomainService : IMyDomainService
{
private readonly IDispatcher _dispatcher;

public MyDomainService(IDispatcher dispatcher)
{
_dispatcher = dispatcher;
}

private void GotResultFromBackgroundThread()
{
_dispatcher.Dispatch(() => DoStuffOnForegroundThread());
}
}

" You need to make sure you are invoking on the actual UI Dispatcher, not necessarily the Current "

您可以参与 the PRISM event aggregator确保您在 UI 线程或基本 Dispatcher.CheckAccess Method

如果你使用 TaskScheduler,那么你应该得到 TaskScheduler.FromCurrentSynchronizationContext在 UI 线程上(例如,在 Window.Loaded 事件处理程序中,您将双击您的表单)并传递/共享到/与任务。

关于c# - 从任务工厂调度的线程更新 WPF 中的 UI 的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16161131/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com