Execute/CanExecute=ICommand=RoutedCmd
route only, no app code, need to find cmdbinding up VTree
Decoupled Design. DelegateCommand, ApplicationCommand implements ICmd
<Button Command="AppCmds.Cut" /> <Window.CmdBindings> has app code
if(..) e.CanExec=true
<CmdBdg Executed="codebhd_appCode" CanExec="cdbh"/> note Execute(d).
routing without xaml VTree
--- target Binding, could be element outside up-VTree
<Button Command="Cut" CmdTarget={Binding Elem=_tb1}
--- or OnApplyTemplate() inject code
btn.Cliked +=(s,e)=>{ApplicationCommands.Cut.Execute(null,__tb1);}
Custom Routed Command --need to set CmdBinding somewhere
static class CmdHost { static RoutedCmd CustCmd;}
public CustomControl1() {
CommandBindins.Add(new CommandBinding(CmdHost.CustCmd, Exec,CanExec));
now CustCmd is injected into WPF Command System to enable the following:
(1) user <Button Command="CmdHost.CustCmd" Target="_ctl1"/>
(2) user Code Behind {Cmd.Host.CustCmd.Exec("Text RontedCmd(param,tgt");}
(3) ctr itself Exec(sender, e) { _ctl1 is updated here}
Custom Control must Implements ICommandSource to support MVVM
propdep snippet, manual modify ICommandSource
install-package relaycommand bring down source
install-package netfx-system.windows.input.delegatecommand
DelegateCommand have ()=>true for CanExec
[TemplatePart(Name = "PART_BDR", Type = typeof(TextBlock))]
public class CustomControl1 : ContentControl, ICommandSource
{
#region Minimum MVVM support---DP Cmd, OnApplyTemp hookup and
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Border b = GetTemplateChild("PART_border") as Border;
b.MouseLeftButtonDown += (s, e) => {
if (Command is RoutedCommand) (Command as RoutedCommand).Execute(CommandParameter, CommandTarget);
else Command.Execute(CommandParameter);
};
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand),
typeof(CustomControl1), new PropertyMetadata((ICommand)null,
new PropertyChangedCallback(OnCommandChanged)));
[TypeConverter(typeof(CommandConverter))]
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
#endregion
#region Only for CanExecute =IsEnabled from VM DelegateCommand
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var cc = d as CustomControl1;
if(cc!= null)
{
cc.OnCommandChanged((ICommand)e.OldValue,(ICommand)e.NewValue);
}
}
EventHandler _persistHandleToAvoidGC;
protected virtual void OnCommandChanged(ICommand oldCmd, ICommand newCmd) // future extension point
{
HookUnhookCommand(oldCmd, newCmd); //hook/unhook for mem clean up
}
private void HookUnhookCommand(ICommand oldCmd, ICommand newCmd)
{
_persistHandleToAvoidGC = new EventHandler((s,e)=> {
// finnally, disable ctl through cmd.CanExe to VM DelegateCmd ()=>T/F
IsEnabled = Command.CanExecute(CommandParameter);
});
if(newCmd!=null) newCmd.CanExecuteChanged += _persistHandleToAvoidGC;
if (oldCmd != null) oldCmd.CanExecuteChanged -= _persistHandleToAvoidGC;
}
#endregion
#region CmdParam/Target are related to WPF Routed Cmd, not MVVM
public object CommandParameter
{
get { return (object)GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(CustomControl1), new PropertyMetadata(null));
public IInputElement CommandTarget
{
get { return (IInputElement)GetValue(CommandTargetProperty); }
set { SetValue(CommandTargetProperty, value); }
}
public static readonly DependencyProperty CommandTargetProperty =
DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(CustomControl1), new PropertyMetadata(null));
#endregion
}
}
<cc:CustomControl1 Command="{Binding TestCommand}" Background="Transparent" />
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
Loaded += (s,e) => // INPC need to set in loaded
{
TestCommand = new DelegateCommand(() =>
{ MessageBox.Show("Command Triggered"); },
() => false); //true=CanExecute
};
}
public event PropertyChangedEventHandler PropertyChanged;
private DelegateCommand _testCommand;
public DelegateCommand TestCommand
{
get { return _testCommand; }
set
{
_testCommand = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("TestCommand"));
}
}
}
Monday, March 28, 2016
WCF custom control--inject into WPF and MVVM Command System
Subscribe to:
Post Comments (Atom)
Nice copy and paster article lol
ReplyDelete