簡體   English   中英

在MVVM Light中將參數動態分配給RelayCommand

[英]Dynamically assigning a parameter to a RelayCommand in MVVM Light

我已經看到了很多使用MVVM Light中的RelayCommand類通過命令傳遞參數的示例,但是我想要的和所見之間有一些細微的差別。

我想創建一些按鈕,使它們都具有關聯的ModuleType。 當他們執行動作時,我想知道它是哪個ModuleType。 而且我想以一種代碼有效的方式執行此操作,因此不必手動創建RelayCommands,而是在foreach循環中執行所有操作,這還因為我不知道在開始時必須創建多少個按鈕。

所以這是代碼。 在我的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;
    }
}

我仍在學習lambda表達式,所以我想我在RelayCommand的初始化上做錯了。

如果執行foreach循環並在lambda表達式中使用loop變量,則將其捕獲。 不幸的是,變量的作用域不正確(至少在C#的較早版本中,此變化隨C#5的變化而變化 (感謝Mafii))。

因此,您需要執行以下操作:

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));
}

關於HB發布的解決方案:不知道為什么它不能與lambda函數一起使用,為什么在按下按鈕時不執行ButtonExecute。 而且我也不理解在foo為空並傳遞給該函數時定義lambda函數(如“ foo => ButtonExecute(foo)”)的邏輯。 但無論如何...

這是我所做的並且正在工作:

模型

<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 (檢查我的初始問題中的其余代碼)

.........

_navBarButtons.Add(new NavButton(mod.ToString(), new RelayCommand<ModuleType>(ButtonExecute), type));

.........

private void ButtonExecute(ModuleType state)
{
    WriteToLog("Command with parameter " + state.ToString());
}

您可以使用Object而不是ModuleType使其更通用。 解決方案不是使用lambda函數,而是在按鈕中定義CommandParameter綁定,並將該值作為execute函數中的參數。 我認為綁定沒有明確定義,這就是為什么我很難理解該值如何達到“ ButtonExecute”的原因,但是按照Dominik Schmidt教程中的步驟進行工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM