Skip to main content
 首页 » 编程设计

c#之WPF 按钮动态命令

2024年08月12日46shangdawei

我有一个 WPF 表单设置如下;

<ListBox x:Name="lbModules" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch"> 
    <ListBox.ItemTemplate> 
        <DataTemplate> 
            <Button Command="{Binding OnClick}"> 
                <StackPanel> 
                    <Image Source="{Binding ModuleIcon}"/> 
                    <Label Content="{Binding ModuleName}"/> 
                </StackPanel> 
            </Button> 
        </DataTemplate> 
    </ListBox.ItemTemplate> 
    <ListBox.ItemsPanel> 
        <ItemsPanelTemplate> 
            <WrapPanel></WrapPanel> 
        </ItemsPanelTemplate> 
    </ListBox.ItemsPanel> 
</ListBox> 

在后面的代码中,lbModules给出一个 List<ModuleButton>作为 ItemsSource,其中 ModuleButton定义如下;

internal class ModuleButton 
{ 
    public ImageSource ModuleIcon {get; set;} 
    public string ModuleName {get; set;} 
    public ICommand OnClick {get; set;} 
} 

我的问题是以动态方式定义 OnClick 命令。我需要这样做,因为我正在使用 MEF,并且 OnClick 事件在技术上位于不同的程序集中。我只需要打电话module.GetForm()但这似乎并不那么简单......

我按如下方式构建 ModuleButton;

Lazy<IModule, IModuleMetadata> moduleCopy = module; 
ModuleButton button = new ModuleButton 
{ 
    ModuleName = moduleCopy.Metadata.ModuleName, 
    ModuleIcon =  
        Imaging.CreateBitmapSourceFromHBitmap(moduleCopy.Value.ModuleButtonIcon.GetHbitmap(), 
            IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()), 
    OnClick = // TODO: Somehow call moduleCopy.Value.GetForm() 
}; 

我一直在广泛搜索,在 Google 中查看各种结果,this是我最新的消息来源之一。

有没有可能做我想做的事?如果是,怎么办?

请您参考如下方法:

好吧,试试我的版本吧,因为Patrick的回答没有实现ICommand的CanExecuteChanged事件所以你不能顺利编译;此外,此 RelayCommand 重载了仅采用一个参数的构造函数 - CanExecute 始终返回 true - 使其更易于使用。

摘自MSDN杂志文章WPF Apps With The Model-View-ViewModel Design Pattern .

public class RelayCommand : ICommand 
{ 
    #region Fields 
 
    readonly Action<object> _execute; 
    readonly Predicate<object> _canExecute; 
 
    #endregion // Fields 
 
    #region Constructors 
 
    /// <summary> 
    /// Creates a new command that can always execute. 
    /// </summary> 
    /// <param name="execute">The execution logic.</param> 
    public RelayCommand(Action<object> execute) 
        : this(execute, null) 
    { 
    } 
 
    /// <summary> 
    /// Creates a new command. 
    /// </summary> 
    /// <param name="execute">The execution logic.</param> 
    /// <param name="canExecute">The execution status logic.</param> 
    public RelayCommand(Action<object> execute, Predicate<object> canExecute) 
    { 
        if (execute == null) 
            throw new ArgumentNullException("execute"); 
 
        _execute = execute; 
        _canExecute = canExecute; 
    } 
 
    #endregion // Constructors 
 
    #region ICommand Members 
 
    [DebuggerStepThrough] 
    public bool CanExecute(object parameter) 
    { 
        return _canExecute == null ? true : _canExecute(parameter); 
    } 
 
    public event EventHandler CanExecuteChanged 
    { 
        add { CommandManager.RequerySuggested += value; } 
        remove { CommandManager.RequerySuggested -= value; } 
    } 
 
    public void Execute(object parameter) 
    { 
        _execute(parameter); 
    } 
 
    #endregion // ICommand Members 
} 

OnClick = new RelayCommand ((o) =>  
    { 
        moduleCopy.Value.GetForm(); 
    });