0

约定难题:

为简单起见,假设我有一个名为 FruitView 的视图,其标签上写着“选择一种水果:”,并在 ListBox 中选择了苹果、橙子、梨等。

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

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

public Fruit CurrentFruit { get; set; }

“水果”本身就是苹果、橙子、梨子等每一个派生出来的接口。

现在,另一个步骤,Apple、Orange、Pear 等 Apple.cs 中的每一个都依赖于名为 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);
    }
}

当在视图中选择“苹果”时,视图的其余按钮、图像等需要对源自 AppleManager 的事件做出反应;when "orange" is selected, the view needs to react to events in OrangeManager.

那么,问题是,将 View 的反应方法连接到 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 派生的,它们实现了这些事件,并有方法来引发它们。

这意味着我必须在每个 VCONF1 等中编写相同的事件行,但这与让多个类继承 INotifyPropertyChanged 相同——这就是我以这种方式设置它的原因)。这也意味着在 VCONF1Manager 中编写相同的事件和引发方法——引发事件链,上层引发事件,上层引发事件,等等,直到 View 可以对其做出反应。VCONF1Manager.CallIncoming -> VCONF1.CallIncoming -> 查看反应

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

其他 VCONF?甚至可能没有经理,只是有自己的方式来确定何时引发这些事件。

View 在被选中时订阅当前 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
    ...
}

所以,我在这里真正要问的是,通过层/抽象链接事件首选/传统方式是什么?

我正在做的工作,但我不禁觉得连续加倍和链接事件并不是最好的方法。

提前致谢。

4

2 回答 2

1

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

如果您的视图需要针对不同类型的水果看起来不同,您应该使用数据模板并让视图在当前水果发生变化时自动配置自己。IE:

<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}"/>

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

于 2013-03-06T20:12:46.400 回答
0

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

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

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

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

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

视图一被选中就连接到当前设备的事件,当这些事件被引发时,视图通过“sender.IncomingCallerID”或“sender.CallStatus”等属性访问这些值。

因此,它基本上遵循 Microsoft 如何在 ListBox 上设置 SelectionChanged,然后您从发件人访问 SelectedValue 属性。

于 2013-03-07T18:44:50.890 回答