通过抽象C#WPF MVVM约定链接事件(我';m所做的工作——是否“正确”?)

通过抽象C#WPF MVVM约定链接事件(我';m所做的工作——是否“正确”?),c#,.net,wpf,events,conventions,C#,.net,Wpf,Events,Conventions,一个难题: 为了简单起见,假设我有一个名为“水果视图”的视图,它的标签上写着“选择一种水果”,列表框中有苹果、橘子、梨等选项 每个项都是一个类的实例(Apple.cs、Orange.cs、Pear.cs等) ViewModel使用绑定属性跟踪选定水果: public Fruit CurrentFruit { get; set; } “水果”本身就是苹果、橘子、梨等的一个接口 现在是另一个步骤,Apple、Orange、Pear等都依赖于名为AppleManager、OrangeManager、

一个难题:

为了简单起见,假设我有一个名为“水果视图”的视图,它的标签上写着“选择一种水果”,列表框中有苹果、橘子、梨等选项

每个项都是一个类的实例(Apple.cs、Orange.cs、Pear.cs等)

ViewModel使用绑定属性跟踪选定水果:

public Fruit CurrentFruit { get; set; }
“水果”本身就是苹果、橘子、梨等的一个接口

现在是另一个步骤,Apple、Orange、Pear等都依赖于名为AppleManager、OrangeManager、PearManager等的静态类,这些类具有方法和事件。这些管理器有着显著的不同,并不是从任何公共基础或接口派生出来的

例如,AppleManager可能有:

public delegate void ColorChangedEventHandler(string color);

public static event ColorChangedEventHandler ColorChanged;

private void RaiseColorChanged(string color)
{
    if (ColorChanged != null)
    {
        ColorChanged(color);
    }
}
在视图中选择“apple”时,视图的其余按钮、图像等需要对源自AppleManager的事件作出反应;选择“橙色”后,视图需要对OrangeManager中的事件作出反应

那么,问题是,将视图的反应方法连接到ViewModel中CurrentFruit的管理器的正确途径是什么

我是说,有可能去:

private void FruitListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    // pseudocode: if apple selected, AppleManager.ColorChanged += new ColorChangedEventHandler(CurrentFruit_ColorChanged);
}

private void CurrentFruit_ColorChanged(string color)
{
    FruitColorTextBox.Text = color;
}
这是不可接受的原因,因为它打破了设计模式,意味着我需要处理各种水果

事实上,我有很多医疗设备,而不是水果选项,我想把接口也用作接口,而不是添加额外的逻辑

我当前的解决方案是向接口VCONF添加事件,如下所示:

public interface VCONF
{
    public static event CallIncomingEventHandler CallIncoming;
    public static event EventArgs CallStarted;
    public static event EventArgs CallEnded;
}
现在,VCONF1、VCONF2、VCONF3等都是从VCONF派生的,它们用has方法来实现这些事件

这意味着我必须在每个VCONF1中写入相同的事件行,等等,但这与让多个类继承INotifyPropertyChanged是一样的——这就是我以这种方式设置它的原因)。它还意味着在VCONF1Manager中编写相同的事件和raise方法——一系列raise事件、上一层raise事件、上一层raise事件等等,直到视图能够对其做出反应为止。VCONF1Manager.CallIncoming->VCONF1.CallIncoming->查看反应

VCONF1订阅VCONF1Manager中的事件,VCONF2订阅VCONF2Manager中的事件,等等

其他VCONF?甚至可能没有经理,只是有自己的方式来决定什么时候该提出这些事件

选中该视图时,该视图订阅当前VCONF的事件:

private void VCONF_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    (this.DataContext as VCONFViewModel).CurrentVCONF = (sender as ListBox).SelectedValue as VCONF;

    (((sender as ListBox).SelectedValue as VCONF).Device as VCONF).CallIncoming += new CallIncomingEventHandler(CurrentVCONF_CallIncoming);
    // same for other events
    ...
}
所以,我在这里真正想问的是,通过层/抽象链接事件的方式是什么,或者说是你首选的/传统的方式

我正在做的工作很有效,但我忍不住觉得把事件对折并连成一行并不是最好的方式


提前感谢。

您的视图应该绑定到视图模型的属性,视图模型中不应该有视图事件处理程序。因此,您的视图应该绑定到其
DataContext
Color
属性,而不是
CurrentFruit\u ColorChanged
事件处理程序,本质上是
fruit.Color
。然后在视图模型中根据属性更改而不是导致更改的事件做出适当的反应

如果您的视图需要为不同类型的水果寻找不同的外观,则应在当前水果发生变化时利用并自动配置视图本身。即:

<Window.Resources>
    <DataTemplate DataType="{x:Type Apple}">
        <!-- ... view for Apples ... -->
    </DataTemplate>
    <DataTemplate DataType="{x:Type Orange}">
        <!-- ... view for Oranges ... -->
    </DataTemplate>
    <DataTemplate DataeType="{x:Type Pear}">
        <!-- ... view for Pears ... -->
    </DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding Path=CurrentFruit}"/>


上面示例中的特定于水果的视图将连接到其数据类型的属性。当视图连接到viewmodel属性而不是viewmodel试图订阅视图事件时,您的管理器概念可能(应该)消失。

正如我在评论中提到的,我按照Microsoft的.NET标准约定重新修改了事件路径

我不再将ViewModel用于此路径,ViewModel仅用于保存视图直接使用并显示的对象,如设备集合(或水果,或其他)

视图基于接口与当前设备对话,并且该接口具有设备将引发到视图的任何事件,使用标准EventHandler,没有数据EventArgs

每个设备都实现这些事件,并在其内部逻辑确定要这样做时引发它们(取决于设备管理器类)

另外,接口和实现的属性包含了我之前试图通过事件传递的数据

一旦选择了视图,它就会连接到当前设备的事件,并且当引发这些事件时,视图会通过“sender.IncomingCallerID”或“sender.CallStatus”等属性访问这些值


因此,它基本上遵循了Microsoft如何在列表框上设置SelectionChanged,然后您可以从sender访问SelectedValue属性。

这是一个不错的想法,但需要大量更改我们的应用程序结构。它是以设备为中心的,因此有许多视图,每个视图都属于一个设备类别,用于连接和显示多个设备的控件,因此每个视图都需要能够通过接口处理这些设备。e、 g.视频会议视图处理视频会议设备的显示和控制,以及具有类似但不相同功能的多种类型摄像机的摄像机视图。继续上述操作,最终结果是,我们需要摄像机视图与当前设备“像CAM一样”对话,这是一个接口,而不是特定于设备的。今天我修改了我如何处理这些事件,并使其遵循微软的战略。也就是说,标准EventArgs事件没有数据,CallStatusChanged事件由设备引发,视图会作出反应并转到“sender.CallStatus”以获取这些值,作为属性。