委托,动作,事件,Lambda表达式和MVVM

本文关键字:MVVM 表达式 事件 动作 委托 Lambda | 更新日期: 2023-09-27 18:07:07

我花了几天时间试图理解WPF和MVVM。它进展得很慢,主要是因为我对事件和东西缺乏了解。下面我将试着解释我对所有这些事情的理解:


方法 -这个很简单,我认为不需要任何解释。任何程序的基本要素。

Delegate -我认为它是方法上的指针。我能想到的只有几个应用程序,我想使用它而不是一个方法。

Action——这个更棘手。我设法找到的信息说,这是一个委托,不返回值…它只是void方法上的指针吗?我不明白那有什么意义

事件 -这个我根本不明白。它是用委托解释的,我不明白它是如何工作的,它是用来干什么的。注意,我使用事件编写winforms应用程序,但它只是从列表中选择所需的事件。

事件处理程序 -更不清楚。

Lambda表达式 -也是使用方法的另一种方式。我明白它不会返回任何东西,我可以在里面传递一些参数,但仍然和void方法没有太大的不同。我已经看到了一些应用程序,比如当使用LINQ时,但我仍然不明白它是如何工作的。


我想首先说我了解MVVM的基本结构,什么是做什么等等。我的问题是,我不理解一些代码,它是如何工作的,因此我不能自己写任何东西。我将使用一些教程作为例子,下面是

S1: https://msdn.microsoft.com/en-us/magazine/dd419663.aspx id0090030

S2: http://social.technet.microsoft.com/wiki/contents/articles/18199.event-handling-in-an-mvvm-wpf-application.aspx

我期望从你们那里得到一些指导或解释,我如何才能接近和理解这些想法,使它们至少对我来说不那么可怕。在这里,我将举一些例子,希望能告诉你我有什么样的问题。


1)第一个来自著名的RelayCommand类的S1:

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

我知道它应该做什么(名字不言自明)。但我不明白这东西是怎么用的?它如何知道什么时候让某些东西可执行,什么时候不能。这些添加和删除"命令"究竟是什么?我试着读了一下,但是没有用。

2)另一个例子S1:

    #region CloseCommand
    /// <summary>
    /// Returns the command that, when invoked, attempts
    /// to remove this workspace from the user interface.
    /// </summary>
    public ICommand CloseCommand
    {
        get
        {
            if (_closeCommand == null)
                _closeCommand = new RelayCommand(param => this.OnRequestClose());
            return _closeCommand;
        }
    }
    #endregion // CloseCommand
    #region RequestClose [event]
    /// <summary>
    /// Raised when this workspace should be removed from the UI.
    /// </summary>
    public event EventHandler RequestClose;
    void OnRequestClose()
    {
        EventHandler handler = this.RequestClose;
        if (handler != null)
            handler(this, EventArgs.Empty);
    }
    #endregion // RequestClose [event]

我知道它应该做什么,我甚至知道这里基本上发生了什么,但我不知道这个"东西"实际上在做什么。OnRequestClose()只是创建处理程序,在我看来不做任何事情来关闭它应该关闭的任何东西。问题是,如果我甚至不知道命令在哪里执行,我怎么能编写自己的命令。

我想这是最后一个例子了,这次是S2:

public ViewModel()
{
    _clickCommand = new DelegateCommand<string>(
        (s) => { /* perform some action */ }, //Execute
        (s) => { return !string.IsNullOrEmpty(_input); } //CanExecute
        );
}

这个问题很简单。它正在使用RelayCommand ctor创建命令(或者至少它在这个项目中的版本,这里称为"DelegateCommand")。我不明白这些和的用法。这是干什么用的?


当然,这不是我所有的问题,但我想这将给我的问题是什么,任何人愿意帮助。我尽我所能解释我的问题,我将非常感谢任何帮助或指导。也许我对自己期望太高了,但我觉得我需要知道所有的东西,才能写出任何严肃的东西。

无论如何,提前感谢大家的帮助。

委托,动作,事件,Lambda表达式和MVVM

对你这个宽泛的问题的一个很长的回答。

让我先用一个简单的方法来研究Events和EventHandler

假设在你的城市组织了一个大型活动,将邀请许多来自你们国家的名人。

让我们以三个客人为例
一号客人是其他客人不认识的人。
客人二是你所在地区的名人,很少有人知道
客人三在你们国家非常有名

考虑以下假设

没有人在等待guest 1 (0 EventHandler)

有四个在等客人2(4)的人,每个人都是等待迎接的事件处理程序

有三个保安人员和10位客人(其中一人)一个人也在等待客人2)等待客人3 (13)EventHandler)

场景1当一号客人到达会场(活动启动),什么也没发生

场景2当客人2到达会场(活动启动)时,四个人走向他/她并问候

场景3当客人3到达(事件)时,你会看到安全部队提供掩护,十个人走向他/她并问候。

简单的观察点
1. 事件只是一个通知发生了什么事情(就像一个带有方法签名的委托)
2. EventHandler是一个动作,用于处理特定事件发生时发生的事情(实现定义的方法签名的方法)通过委托)
3.一个事件可以有多个事件处理程序(例如…场景2、3)。因此,下面的代码示例

中的语法+=

下面的代码将回答你的一些基本问题

class Program
{
    static void Main(string[] args)
    {
        var test = new Example();
        Console.ReadLine();
    }
}

class Example
{
    //This is the event definition
    delegate void ActionDelegate(string input1, string input2);
    // Two event handler which implements the signature of the event
    void ActionMethod(string a, string b)
    {
        Console.WriteLine(a + " " + b);
    }
    void ActionMethod2(string c, string d)
    {
        Console.WriteLine("Wow one more function called with parameter {0} and {1}", c, d);
    }
    delegate Tuple<string, string> LamdaDelegate(string input1, string input2);
    public Example()
    {
        //Did not declare any delegate member variable explicitly.
        //Clean and easy to understand
        Action<string, string> action = ActionMethod;
        // Had to define the delegate with method signature explicitly before using it
        ActionDelegate actionDelegate = ActionMethod; 
        actionDelegate += ActionMethod2; // Attaching more event handlers to the event
        //The below lambda expression implicitly means that it will take two inputs each of type string
        // and does not return anything. 
        //The type information is implicitly derived from the method signature of the delegate
        actionDelegate += (a, b) => Console.WriteLine("Called using lambda expression");

        //Below is a Lambda expression in which s and e each is of type string 
        //Since the return type of the delegate is Tuple<string,string> the same is returned by the expression
        //Lambda expression is using a delegate without defining a delegate explicitly. 
        LamdaDelegate myTuple = (s, e) => { return Tuple.Create(s, e); };
        //The above Lambda can be rewritten as
        myTuple += delegate (string a, string b) { return Tuple.Create(a, b); };
        //Invoking the event handlers. The event handlers are executed automatically when ever the event occurs 
        action("Hi", "called from action");
        actionDelegate("Hi", "called using explicitly defined delegate");
    }
}

为什么要使用委托?
在上面的示例中,您看到两个不同的委托使用ActionMethod(读Event)。如果没有委托,上面的例子将是肮脏和不可读的。
上面的示例还展示了Action,它简化了显式定义委托的需要。

现在进入命令页
在MVVM中,传统的事件用Command代替,事件参数(读委托方法签名)用CommandParameter代替

在你的第三个问题中,DelegateCommand有一个类型参数string。你看到的是一个变量它存储了从UI发送过来的输入字符串。现在由您来决定是使用输入(s)还是完全忽略它。在CanExecute部分中,您可以看到,即使传递了输入(s),它也忽略了它,并使用了另一个成员变量_input

第二个问题定义了一个事件RequestClose,它附加在链接的图7中的事件处理程序中。还可以观察到,在同一张图中,MenuItemViewModel中的CloseCommand绑定在一起。
所以现在当你点击MenuItem时,CloseCommand被调用,然后它调用OnRequestClose函数。该函数检查的第一件事是是否有人对MainWindow正在侦听的事件RequestClose感兴趣(读取侦听),并因此调用window.Close()

如果需要更多的说明,请告诉我。

编辑

上面的代码示例仅针对Action<T>delegate

通俗点说,让我这么说

如果我想做一些基于一些外部动作 我将使用事件。我将定义一个事件并将其连接到EventHandler,然后等待动作发生。(在上面的例子中,我不知道客人什么时候到达,但无论他们何时到达,EventHandler 都会自动响应)

另一方面,如果我想基于代码中定义的一些内部条件同时调用单个/多个函数,我会使用delegate。在上面的代码示例中,可以看到我必须手动调用委托

请忽略Tuple,因为它只是一个没有实际重要性的返回值。

编辑2

<

场景strong> (_) 或 (s) 是相似的。都意味着你将得到一个参数作为输入,但在第一种情况下,开发人员试图说这个参数不会被使用或忽略,而在(s)中,他们打算使用它

你不能只使用(),因为这意味着lambda表达式不包含任何输入参数,这是错误的,因为定义说它将接收string作为输入。

1。委托

我认为它是方法

上的指针

正确的。然而,由于c#是强类型的,您需要定义该方法必须具有哪些参数和返回类型。这就是委托。

我能想到的只有几个应用程序,我想使用它方法。

这不是关于方法vs委托的问题。当您需要将method作为参数传递时,则使用delegate定义参数。

2。行动

Action是委托的具体类型。虽然委托可以引用任何方法,但Action说,它是返回类型为void的无参数方法。Action<string>表示参数类型为字符串。Action<string, int>表示方法的第一个参数必须是string类型,第二个参数必须是int类型。

委托的另一个具体例子是Func委托。Func<bool>表示该方法没有参数并返回bool值。Func<string, bool>表示有一个string类型的输入参数,它返回bool。

EventHandler只是另一个委托,它代表了具有void返回类型和两个输入参数的方法:object和EventArgs

3。事件

想想按钮。单击事件。微软负责Button类的程序员必须提供一种方法来通知你的程序,按钮被点击了。他们定义了一个事件,你可以通过提供一个在事件发生时执行的方法来处理事件。这个方法叫做eventhandler。

4。EventHandler 被用作分配给事件的方法的通用名称,或者是定义输入和输出参数的具体委托,或者用作。

e。g: Button.Click += DoSomehing;"Click"为事件。方法DoSomething是一个事件处理程序。它必须返回void,并且有两个类型为object和EventArgs的输入参数,因为当你查看click事件的定义时,你可以看到具体的委托类型是EventHandler(或RoutedEventHandler -只是WPF中在某些事件中使用的另一个委托)。

5。Lambda表达式

非常简单。Lambda表达式只是编写方法的另一种语法。编译器会把lambda转换成方法。lambda只是语法糖。

后面的方法和lambda相等

bool IsGreaterThan5(int number)
{
  return number > 5;
}
var isGreaterThan5 = new Func<int, bool>(number => number > 5);

为例,如果您有一个整数数组,那么您可以使用Where linq扩展方法来筛选该数组。智能感知告诉你,Where方法的参数是Func<int, bool>。因此,您需要传递一个方法,该方法接受一个int类型的形参并返回bool值。

int[] numbers = new []{ 1, 2, 3 4, 5, 6, 7 };
var filteredNumbers = numbers.Where(IsGreaterThan5); //method IsGreaterThan5 is defined in previus example
//just another syntax:
var filteredNumbers = numbers.Where(number => number > 5);
//just another syntax:
var filteredNumbers = numbers.Where(new Func<int, bool>(number => number > 5));
//just another syntax:
Func<int, bool> isGreaterThan5 = i => i > 5; //it does not matter how you name the input parameter
var filteredNumbers = numbers.Where(isGreaterThan5);