Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 基本理解:将带参数的方法绑定到控件_C#_Wpf_Data Binding_Listbox_Command - Fatal编程技术网

C# 基本理解:将带参数的方法绑定到控件

C# 基本理解:将带参数的方法绑定到控件,c#,wpf,data-binding,listbox,command,C#,Wpf,Data Binding,Listbox,Command,我有一个窗口,其中有一个列表框,它绑定到列表的一个实例。类MyThing包含一个属性Name,该属性显示在列表框中 我还有一个按钮,我希望在单击该按钮时运行以下方法: void RunMe(MyThing m) { ... } 作为此方法的参数,我想使用列表框中的SelectedItem 我该怎么做? 这是我的MyWindow类的XAML文件: <Window x:Class="MyProject.MyWindow" xmlns="http://schemas.micro

我有一个窗口,其中有一个
列表框
,它绑定到
列表
的一个实例。类
MyThing
包含一个属性
Name
,该属性显示在
列表框中

我还有一个
按钮
,我希望在单击该按钮时运行以下方法:

void RunMe(MyThing m) { ... }
作为此方法的参数,我想使用
列表框中的
SelectedItem

我该怎么做?

这是我的
MyWindow
类的XAML文件:

<Window x:Class="MyProject.MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel>
        <ListBox x:Name="lb" ItemsSource="{Binding MyThingList}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Button Content="Run command!" Command="{Binding RunCommand}"/>
    </StackPanel>
</Window>
正如你们这些有经验的人可能看到的那样,我真的不知道我在做什么。以下是一些具体问题:


  • 为什么我不能简单地将按钮绑定到每次单击时调用的任何方法?为什么它必须是一个命令,它的好处是什么?(我知道命令可以自动跟踪其可执行性,当无法执行时按钮会变灰,但现在我不关心这一点。我也知道它可以绑定到事件,但似乎此事件必须在codebehind中定义,我希望保留为空。如果我错了,请纠正我。)

  • 如何将我的
    RunMe
    方法连接到
    MyVM
    构造函数中的命令
    RunCommand
    ?(我试过
    RunCommand=newroutedUICommand(“RunMe”,“RunMe”,typeof(MyVm));
    ,但是按钮变灰了。我也试过
    typeof(MyWindow)
    typeof(Window)
    ,但还是变灰了。)

  • 假设我实现了这一点,点击按钮就会调用方法
    RunMe
    。如何将
    SelectedItem
    ListBox
    传递到
    RunMe
    方法?(我知道我可以将按钮的
    DataContext
    更改为
    DataContext=“{Binding Path=SelectedItem,ElementName=lb}”
    ,但随后可能找不到该命令,我仍然不知道如何使按钮将此选定项移交给该方法。)

  • 我的方法是否有根本性的问题?我仍在尝试了解任何东西(一般的GUI编程、事件/命令、WPF、MVVM模式——同时对我来说都是新的),所以如果您有更好的方法,请告诉我

  • PS:请随意将标题改为更具表现力的内容。我有很多问题,很难把它归结为一个


  • 为什么我不能简单地将按钮绑定到每次单击时调用的任何方法?为什么它必须是一个命令,它的好处是什么
  • 命令
    模式主要用于MVVM,因为正如您所说,它允许视图和viewmodel共享信息,比如
    CanExecute
    类型的方法;您可以通过使用按钮的
    单击事件将按钮“绑定”到任何方法,而无需使用此模式

    此外,命令是视图和视图模型之间的抽象;如果您可以使用任何方法,您的视图可以。。。好的,使用viewmodel公开的任何方法

    也就是说,这只是一种模式,你不必使用它。看一个关于Caliburn.Micro的例子,它似乎不使用命令

  • 如何将RunMe方法连接到MyVM构造函数中的命令RunCommand
  • 我们需要您的ICommand实现来回答这个问题

  • 假设我实现了这个功能,点击按钮就会调用RunMe方法。如何将SelectedItem从ListBox传递到RunMe方法
  • 在MVVM中,考虑数据,而不是视图。
    您的viewmodel中应该有一个
    列表
    (或者一个
    可观察集合
    ,如果需要实时修改的话),其中包含列表框的ItemsSource在XAML中应该绑定到的项。 同样,在viewmodel中需要CurrentItem属性,ListBox的SelectedItem将绑定到该属性

  • 我的方法是否有根本性的问题?我仍在努力掌握一切

  • 就其本身而言,WPF和MVVM并没有什么错,这是一个很好的学习。您需要一些时间才能适应它们。

    ICommand
    比简单的方法调用更灵活、更强大。如果您确实需要一个简单的方法调用(嗯,有点简单…ish),您只需处理按钮的
    单击
    事件:

    protected void RunCommandButton_Click(object sender, RoutedEventArgs args)
    {
        var vm = (MyVM)DataContext;
        var selectedThing = lb.SelectedItem as MyThing;
    
        if (selectedThing != null)
        {
            vm.RunMe(selectedThing);
        }
    }
    
    这不是“正确的方法”,但有时它已经足够好了。我们并不总是需要建造帕台农神庙。有时我们只需要一块油布来挡住柴火上的雨水

    如果您正在使用命令(并且您应该学习使用命令),则应该使用
    DelegateCommand
    来实现您的命令。WPF本应在开箱即用的情况下包含此类内容,但不幸的是,他们没有。他们所提供的是非常痛苦的,你自己去弄清楚,虽然我没用过。下面我提供了一个非常简单的非通用版本

    private DelegateCommand _runCommand;
    public ICommand RunCommand {
        get {
            if (_runCommand == null)
            {
                _runCommand = new DelegateCommand(RunCommandExecute, ExecuteCanExecute);
            }
            return _runCommand;
        }
    }
    
    protected void RunCommandExecute(Object parameter)
    {
        //  Do stuff
    }
    
    protected bool RunCommandCanExecute(Object parameter)
    {
        //  Return true if command can be executed
        return parameter != null;
    }
    
    这样绑定:

    <Button 
        Content="Run command!" 
        Command="{Binding RunCommand}"
        CommandParameter="{Binding SelectedItem, ElementName=lb}"
        />
    
    
    
    另外,对列表项使用
    可观察集合
    ,而不是
    列表
    。这样,当您添加和删除列表项时,列表框将自动更新

    DelegateCommand.cs

    using System;
    using System.Windows.Input;
    
    namespace HollowEarth.MVVM
    {
        public class DelegateCommand : ICommand
        {
            private readonly Predicate<object> _canExecute;
            private readonly Action<object> _execute;
    
            public event EventHandler CanExecuteChanged;
    
            #region Constructors
            public DelegateCommand(Action<object> execute)
                : this(execute, null)
            {
            }
    
            public DelegateCommand(Action execute)
                : this(o => execute(), null)
            {
            }
    
            public DelegateCommand(Action execute, Func<bool> canExecute)
            {
                _execute = o => execute();
                _canExecute = o => canExecute();
            }
    
            public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
            {
                _execute = execute;
                _canExecute = canExecute;
            }
            #endregion Constructors
    
            public virtual bool CanExecute(object parameter)
            {
                if (_canExecute == null)
                {
                    return true;
                }
    
                return _canExecute(parameter);
            }
    
            public virtual void Execute(object parameter)
            {
                _execute(parameter);
            }
    
            public void RaiseCanExecuteChanged()
            {
                CanExecuteChanged?.Invoke(this, EventArgs.Empty);
            }
        }
    }
    
    使用系统;
    使用System.Windows.Input;
    名称空间hollowarth.MVVM
    {
    公共类DelegateCommand:ICommand
    {
    私有只读谓词_canExecute;
    私有只读操作\u执行;
    公共事件处理程序CanExecuteChanged;
    #区域构造函数
    公共DelegateCommand(操作执行)
    :此(执行,空)
    {
    }
    公共DelegateCommand(操作执行)
    :这(o=>execute(),null)
    {
    }
    公共DelegateCommand(操作执行,Func canExecute)
    {
    _execute=o=>execute();
    _canExecute=o=>canExecu
    
    using System;
    using System.Windows.Input;
    
    namespace HollowEarth.MVVM
    {
        public class DelegateCommand : ICommand
        {
            private readonly Predicate<object> _canExecute;
            private readonly Action<object> _execute;
    
            public event EventHandler CanExecuteChanged;
    
            #region Constructors
            public DelegateCommand(Action<object> execute)
                : this(execute, null)
            {
            }
    
            public DelegateCommand(Action execute)
                : this(o => execute(), null)
            {
            }
    
            public DelegateCommand(Action execute, Func<bool> canExecute)
            {
                _execute = o => execute();
                _canExecute = o => canExecute();
            }
    
            public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
            {
                _execute = execute;
                _canExecute = canExecute;
            }
            #endregion Constructors
    
            public virtual bool CanExecute(object parameter)
            {
                if (_canExecute == null)
                {
                    return true;
                }
    
                return _canExecute(parameter);
            }
    
            public virtual void Execute(object parameter)
            {
                _execute(parameter);
            }
    
            public void RaiseCanExecuteChanged()
            {
                CanExecuteChanged?.Invoke(this, EventArgs.Empty);
            }
        }
    }