[英]Dynamically assigning a parameter to a RelayCommand in MVVM Light
I've seen quite a few example of passing a parameter through a command using the RelayCommand class in MVVM Light, but there's one slight difference between what i want and what i have seen. 我已经看到了很多使用MVVM Light中的RelayCommand类通过命令传递参数的示例,但是我想要的和所见之间有一些细微的差别。
I want to create a few buttons where all have them have a ModuleType associated. 我想创建一些按钮,使它们都具有关联的ModuleType。 And when their action is executed i want to know which ModuleType it is.
当他们执行动作时,我想知道它是哪个ModuleType。 And i wanted to do this in a code efficient way, so not having to create the RelayCommands manually, but instead do everything in a foreach loop, also because i don't know how many buttons i have to create at start.
而且我想以一种代码有效的方式执行此操作,因此不必手动创建RelayCommands,而是在foreach循环中执行所有操作,这还因为我不知道在开始时必须创建多少个按钮。
So here is the code. 所以这是代码。 In my ViewModel
在我的ViewModel中
public ModuleSelectionViewModel(MachineStatusModel model, int order, List<ModuleType> modules) : base(model)
{
........
// create button for each of the modules
foreach (ModuleType mod in modules)
{
_navBarButtons.Add(new NavButton(mod.ToString(), new RelayCommand<ModuleType>(exec => ButtonExecute(mod)), mod));
}
RaisePropertyChanged("NavBarButtons");
}
// Binding to the Model
public ObservableCollection<NavButton> NavBarButtons
{
get { return _navBarButtons; }
}
// Execut Action
public void ButtonExecute(ModuleType mod)
{
WriteToLog("Selected " + mod.ToString());
}
// Support class
public class NavButton
{
public string ButtonContent { get; set; }
public ICommand ButtonCommand { get; set; }
public ModuleType ButtonModuleType;
public NavButton(string content, ICommand relay, ModuleType moduleType)
{
this.ButtonContent = content;
this.ButtonCommand = relay;
this.ButtonModuleType = moduleType;
}
}
I'm still learning about lambda expressions, so i guess i am doing something wrong on the initialization of the RelayCommand. 我仍在学习lambda表达式,所以我想我在RelayCommand的初始化上做错了。
If you do a foreach
loop and use the loop variable inside a lambda expression you capture it. 如果执行
foreach
循环并在lambda表达式中使用loop变量,则将其捕获。 Unfortunately the variable is scoped incorrectly (at least in older versions of C#, this changes with C# 5 (thanks, Mafii)). 不幸的是,变量的作用域不正确(至少在C#的较早版本中,此变化随C#5的变化而变化 (感谢Mafii))。
So you need to do something like: 因此,您需要执行以下操作:
foreach (ModuleType mod in modules)
{
// New variable that is locally scoped.
var type = mod;
_navBarButtons.Add(new NavButton(mod.ToString(),
new RelayCommand<ModuleType>(param => ButtonExecute(type)), type));
}
Regarding the solution HB posted: not sure why it was not working with lambda functions, why the ButtonExecute was not being execute when the button was pressed. 关于HB发布的解决方案:不知道为什么它不能与lambda函数一起使用,为什么在按下按钮时不执行ButtonExecute。 And also i don't understand the logic of defining a lambda function like 'foo => ButtonExecute(foo)' when foo is empty and being passed to the function.
而且我也不理解在foo为空并传递给该函数时定义lambda函数(如“ foo => ButtonExecute(foo)”)的逻辑。 But anyway...
但无论如何...
This is what i did and is working: 这是我所做的并且正在工作:
Model 模型
<ItemsControl Name="NavButtonsItemsControl" ItemsSource="{Binding NavBarButtons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding ButtonContent}" CommandParameter="{Binding ButtonModuleType}" Command="{Binding ButtonCommand}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ViewModel (check the rest of the code in my initial question) ViewModel (检查我的初始问题中的其余代码)
.........
_navBarButtons.Add(new NavButton(mod.ToString(), new RelayCommand<ModuleType>(ButtonExecute), type));
.........
private void ButtonExecute(ModuleType state)
{
WriteToLog("Command with parameter " + state.ToString());
}
You can make this more generic by using Object instead of ModuleType. 您可以使用Object而不是ModuleType使其更通用。 And the solution, instead of using a lambda function, is defining a CommandParameter binding in the button and getting that value as the parameter in the execute function.
解决方案不是使用lambda函数,而是在按钮中定义CommandParameter绑定,并将该值作为execute函数中的参数。 I don't think that binding is explicitly defined, that's why i was having a hard time understanding how the value was reaching 'ButtonExecute', but following the steps in Dominik Schmidt tutorial it worked.
我认为绑定没有明确定义,这就是为什么我很难理解该值如何达到“ ButtonExecute”的原因,但是按照Dominik Schmidt教程中的步骤进行工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.