通过参考传递财产

时间:2018-01-30 14:32:14

标签: c# wpf

我有许多进度条,每个进度条都绑定到它们自己的int属性,这会更新它们的进度。在幕后,我有一个多次运行的方法,它处理(循环数据)我用来更新更新进度条的属性。

我遇到的问题是您无法将属性传递给该方法。我可以创建该方法的多个副本,每个副本都引用每个进度条的特定属性,但这需要大量重复的代码。如何建议我将属性传递给方法?

基本上这就是我想要做的事情,但很明显,通过ref传递财产不会起作用。

Method(fileList, errorList, _ViewModel.ProgressBarProp1);
Method(fileList, errorList, _ViewModel.ProgressBarProp2);
...

private static void Method(IEnumerable<string> fileList, List<Tuple<string, 
    string>> errorList, ref int PropertyInt)
{
    foreach (var file in fileList)
    {
        if (!File.Exists(file))
        {
            errorList.Add(new Tuple<string, string>(file,
                " does not exist in the folder"));
        }

        PropertyInt++;
    }
}

我见过this question,但这涉及到Strings,我还没有能够为整数方案实现任何解决方案。

更新

在下面实现Mike的解决方案是允许从方法中访问该属性,但我对我同时运行它的方式有一些奇怪的行为。

我实现这样的代码,两个方法同时运行但增加相同的属性值(即两者都与同一个进度条相关联)。

var taskList = new List<Task>
{
    Task.Run(() =>
    {
        Method1(fileList, errorList, p => _ViewModel.ProgressBarProp1 = p);
    }),
    Task.Run(() =>
    {
        Method2(fileList, errorList, p => _ViewModel.ProgressBarProp1 = p);
    })
};
await Task.WhenAll(taskList.ToArray());

但是,只有一个似乎在更新。会是什么原因并且有解决方法吗?

1 个答案:

答案 0 :(得分:0)

ref int替换为Action<int>代表。进行后,使用新的进度值调用委托。在呼叫站点,传入一个带有新进度值的lambda并将其分配给您的属性。

Method(fileList, errorList, p => _ViewModel.ProgressBarProp1 = p);

private static void Method(
    IEnumerable<string> fileList,
    List<Tuple<string, string>> errorList,
    Action<int> reportProgress)
{
    var progress = 0;

    foreach (var file in fileList)
    {
        if (!File.Exists(file))
        {
            errorList.Add(new Tuple<string, string>(file,
                " does not exist in the folder"));
        }

        reportProgress?.Invoke(++progress);
    }
}

如果您要响应UI线程的进度但是从另一个线程报告它,您应该确保您的回调将自己封送到UI线程上。您可以使用简单的辅助方法完成此操作:

public static class DispatcherHelper
{
    public static Action<T> MakeInvoker<T>(
        this Dispatcher dispatcher,
        Action<T> action,
        DispatcherPriority priority = DispatcherPriority.Normal)
    {
        return o => dispatcher.BeginInvoke(priority, action, o);
    }
}

然后,按如下方式修改您的调用:

var dispatcher = Application.Current.Dispatcher;
var reportProgress = dispatcher.MakeInvoker<int>(p => _ViewModel.ProgressBarProp1 = p);

await Task.WhenAll(
    Task.Run(() => Method1(fileList, errorList, reportProgress)),
    Task.Run(() => Method2(fileList, errorList, reportProgress)));