委托,动作,事件,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")。我不明白这些和的用法。这是干什么用的?
当然,这不是我所有的问题,但我想这将给我的问题是什么,任何人愿意帮助。我尽我所能解释我的问题,我将非常感谢任何帮助或指导。也许我对自己期望太高了,但我觉得我需要知道所有的东西,才能写出任何严肃的东西。
无论如何,提前感谢大家的帮助。
对你这个宽泛的问题的一个很长的回答。
让我先用一个简单的方法来研究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中的事件处理程序中。还可以观察到,在同一张图中,MenuItem
与ViewModel
中的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);