c# - MVVM with dynamic commands -
i need create class able create dynamic commands can bind to. have highly dynamic application plugins, developer creates plugin in backend , controls things backend. frontend created in different "remote" application has backend datacontext. here's example (not full example), show want do:
<window x:class="wpfapplication7.mainwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" title="mainwindow" height="350" width="525"> <grid> <button command="{binding pressme}">pressme</button> </grid> </window> namespace wpfapplication7 { /// <summary> /// interaction logic mainwindow.xaml /// </summary> public partial class mainwindow : window { taskviewmodel model = new taskviewmodel(); public mainwindow() { initializecomponent(); datacontext = model; model.addcommand("pressme", (o) => { console.writeline("test"); }); } } }
so question is, how create this, if xaml needs "well-defined" or "known" properties on binding can at.
i thought of taskviewmodel , implements iexpando, somehow reflection not performed when hooking iexpando methods. there other ways this.
thanks martin
as always, items-based uis in wpf implemented using itemscontrol
, , leveraging data templating, regardless of visual appearance intended each item, or actual behavior of underlying classes.
in case, you're looking dynamic collection of commands:
// class not implemented. replace own delegatecommand or // grab icommand implementation of known mvvm frameworks out there. // exists sake of example. public class command : icommand { private readonly action action; public string displayname { get; private set; } public bool canexecute(object parameter) { return true; } public event eventhandler canexecutechanged; public void execute(object parameter) { action(); } public command(string displayname, action action) { this.action = action; this.displayname = displayname; } }
viewmodel:
public class viewmodel { public observablecollection<command> commands { get; private set; } public viewmodel() { commands = new observablecollection<command>(); } // add commands @ point @ runtime. public void addsomecommands() { commands.add(new command("command1", () => messagebox.show("this command1!"))); commands.add(new command("command2", () => messagebox.show("this command2!!"))); commands.add(new command("command3", () => messagebox.show("this command3!!!"))); commands.add(new command("command4", () => messagebox.show("this command4!!!!"))); } }
then can create itemscontrol shows button
s each command item:
<window x:class="wpfapplication22.mainwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" title="mainwindow" height="350" width="525"> <itemscontrol itemssource="{binding commands}" verticalalignment="top"> <itemscontrol.itemspanel> <itemspaneltemplate> <stackpanel orientation="horizontal"/> </itemspaneltemplate> </itemscontrol.itemspanel> <itemscontrol.itemtemplate> <datatemplate> <button command="{binding}" content="{binding displayname}" margin="5"/> </datatemplate> </itemscontrol.itemtemplate> </itemscontrol> </window>
code behind:
public partial class mainwindow : window { public mainwindow() { initializecomponent(); var vm = new viewmodel(); vm.addsomecommands(); this.datacontext = vm; } }
result:
edit:
if need bind these commands hotkeys, add property command:
public key hotkey { get; set; }
and add in code behind:
foreach (var c in vm.commands) this.inputbindings.add(new keybinding(c, c.hotkey, modifierkeys.none));
Comments
Post a Comment