Isa*_*avo 10 c# wpf lambda closures
最近我对lambda表达式和变量捕获有点奇怪.代码是使用.NET 4.5(VS2012)的WPF/MVVM应用程序.我正在使用我的viewmodel的不同构造函数来设置a的回调RelayCommand(此命令将绑定到我视图中的菜单项)
实质上,我有以下代码:
public class MyViewModel : ViewModelBase
{
public MyViewModel(Action menuCallback)
{
MyCommand = new RelayCommand(menuCallback);
}
public MyViewModel(Func<ViewModelBase> viewModelCreator)
// I also tried calling the other constructor, but the result was the same
// : this(() => SetMainContent(viewModelCreator())
{
Action action = () => SetMainContent(viewModelCreator());
MyCommand = new RelayCommand(action);
}
public ICommand MyCommand { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
然后使用以下方法创建上述实例:
// From some other viewmodel's code:
new MyViewModel(() => new SomeViewModel());
new MyViewModel(() => new SomeOtherViewModel());
Run Code Online (Sandbox Code Playgroud)
然后将它们绑定到WPF菜单 - 每个菜单项都有一个MyViewModel实例作为其数据上下文.奇怪的是菜单只运行一次.无论我尝试过哪个项目,它都会调用适当的Func<ViewModelBase>- 但只有一次.如果我试图再次选择另一个菜单项或甚至同一个项目,它根本不起作用.VS调试输出中没有任何调用和输出有关任何错误.
我知道循环中变量捕获的问题,所以我猜测这个问题是相关的,所以我的VM改为:
public class MyViewModel : ViewModelBase
{
public MyViewModel(Action buttonCallback)
{
MyCommand = new RelayCommand(buttonCallback);
}
private Func<ViewModelBase> _creator;
public MyViewModel(Func<ViewModelBase> viewModelCreator)
{
// Store the Func<> to a field and use that in the Action lambda
_creator = viewModelCreator;
var action = () => SetMainContent(_creator());
MyCommand = new RelayCommand(action);
}
public ICommand MyCommand { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
并以同样的方式称呼它.现在一切正常.
只是为了好玩,我还Func<ViewModelBase>通过Action在MyViewModel构造函数的外部创建适当的方法来解决整个构造函数:
// This code also works, even without the _creator field in MyViewModel
new MyViewModel(() => SetMainContent(new SomeViewModel()));
new MyViewModel(() => SetMainContent(new SomeOtherViewModel()));
Run Code Online (Sandbox Code Playgroud)
所以我设法让它工作,但我仍然好奇为什么它这样工作.为什么编译器没有Func<ViewModelBase>在构造函数中正确捕获?
我猜下面的代码也可以工作
public MyViewModel(Func<ViewModelBase> viewModelCreator)
{
var action = () => { creator = viewModelCreator; SetMainContent(creator()); };
MyCommand = new RelayCommand(action);
}
Run Code Online (Sandbox Code Playgroud)
如果是这样,那么第一种方式不起作用的原因是您实际上并没有关闭变量viewModelCreator,而是关闭了调用它的结果。
我仍在摆弄 LINQPad 中的代码,但实际上我似乎没有遇到与您相同的问题。也许这是特定于 的东西RelayCommand。你能发布更多你的代码吗?
| 归档时间: |
|
| 查看次数: |
446 次 |
| 最近记录: |