我正在尝试在我目前正在开发的新 WPF .NET Framework 应用程序中使用 Akka.NET。
大多数情况下,在您的应用程序中使用 actor 的过程似乎很容易解释,但是当涉及到在应用程序 View 级别实际使用 actor 输出时,我有点卡住了。
具体来说,关于如何在 actor 中处理接收和处理事件似乎有两种选择。
创建一个具有公开事件处理程序的参与者。所以也许是这样的:
public class DoActionActor : ReceiveActor { public event EventHandler<EventArgs> MessageReceived; private readonly ActorSelection _doActionRemoteActor; public DoActionActor(ActorSelection doActionRemoteActor) { this._doActionRemoteActor = doActionRemoteActor ?? throw new ArgumentNullException("doActionRemoteActor must be provided."); this.Receive<GetAllStuffRequest>(this.HandleGetAllStuffRequestReceived); this.Receive<GetAllStuffResponse>(this.HandleGetAllStuffResponseReceived); } public static Props Props(ActorSystem actorSystem, string doActionRemoteActorPath) { ActorSelection doActionRemoteActor = actorSystem.ActorSelection(doActionRemoteActorPath); return Akka.Actor.Props.Create(() => new DoActionActor(doActionRemoteActor)); } private void HandleGetAllStuffResponseReceived(GetAllTablesResponse obj) { this.MessageReceived?.Invoke(this, new EventArgs()); } private void HandleGetAllStuffRequestReceived(GetAllTablesRequest obj) { this._doActionRemoteActor.Tell(obj, this.Sender); } }
因此基本上您可以创建 View 并通过执行类似这样的操作来调用任何调用 _doActionActor.Tell(new GetStuffRequest());
然后通过事件处理程序处理输出。这很好用,但似乎打破了 Akka.NET 鼓励的“Actors‘无处不在’模型”,我不确定这种方法对并发性的影响。
另一种方法似乎是让我的 ViewModels 本身就是 Actor 。所以基本上我有一些看起来像这样的东西。
public abstract class BaseViewModel : ReceiveActor, IViewModel { public event PropertyChangedEventHandler PropertyChanged; public abstract Props GetProps(); protected void RaisePropertyChanged(PropertyChangedEventArgs eventArgs) { this.PropertyChanged?.Invoke(this, eventArgs); } } public class MainWindowViewModel : BaseViewModel { public MainWindowViewModel() { this.Receive<GetAllTablesResponse>(this.HandleGetAllTablesResponseReceived); ActorManager.Instance.Table.Tell(new GetAllTablesRequest(1), this.Self); } public override Props GetProps() { return Akka.Actor.Props.Create(() => new MainWindowViewModel()); } private void HandleGetAllTablesResponseReceived(GetAllTablesResponse obj) { } }
这样我就可以直接在 Actor 本身(实际上是我的 View 模型)中处理 Actor 事件。
我在尝试这样做时遇到的问题是正确配置我的 Ioc (CaSTLe Windsor) 以正确构建 Akka.NET 实例。
所以我有一些代码来创建看起来像这样的 Akka.NET 对象
Classes.FromThisAssembly()
.BasedOn<BaseViewModel>()
.Configure(config => config.UsingFactoryMethod((kernel, componentModel, context) =>
{
var props = Props.Create(context.RequestedType);
var result = ActorManager.Instance.System.ActorOf(props, context.RequestedType.Name);
return result;
}))
这在实际创建 IActorRef
实例时效果很好,但不幸的是我无法将 actor 引用转换回我需要的实际对象(在本例中为 BaseViewModel
)。
因此,如果我尝试执行此操作,return (BaseViewModel)result;
我会得到一个无效的转换异常。这显然是有道理的,因为我得到的是 IActorRef
对象而不是 BaseViewModel
。
所以总而言之,我希望能回答两个问题。
在 MVVM 应用程序中处理 Akka.NET actor 的最佳方式是什么,特别是在处理接收到的消息和处理显示输出时。
有没有一种方法可以正确配置我的 Ioc 系统来创建
IActorRef
实例并将其添加到系统中,但返回的实际父 actor 对象具体实现的实例>BaseViewModel
?
最佳答案
以下是我正在使用的当前解决方案,希望有人能提出更好的建议。
基本上我已经放弃了让我的 View 成为 Actor 的尝试,目前决定使用一个接口(interface)在 ViewModel
和 Actor
之间进行通信。
目前的解决方案是这样的:
public class MainWindowViewModel : BaseViewModel, ITableResponseHandler
{
public void HandleResponse(IEnumerable<Entity> allEntities) { }
}
public interface ITableResponseHandler
{
void HandleResponse(IEnumerable<Entity> allEntities);
}
public class MyActor : ReceiveActor
{
public MyActor(ITableResponseHandler viewModel)
{
this.Receive<GetAllEntitiesResponse>(this.HandleGetAllEntitiesResponseReceived);
}
private void HandleGetAllEntitiesResponseReceived(GetAllTablesResponse obj)
{
this._ViewModel.HandleTablesResponse(obj.Result);
}
}
虽然我不觉得这很理想,但它基本上让我避免了所有额外的复杂性,即尝试让我的 View 模型本身成为 Actor ,同时充分地将 Actor 与 View 解耦。
我希望其他人遇到过这个问题,并且可能能够提供一些见解,以便更好地解决在 MVVM 应用程序中处理 Akka.NET 输出的问题。
关于c# - Akka.NET 和 MVVM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59015721/