6

我的 WPF 项目将像这样组织:

Screens
   Group1
      Screen1
         View.xaml
         ViewModel.cs
   Group2
      Screen2
         View.xaml
         ViewModel.cs

为了显示Screen1Screen2我将使用这样的东西:ScreenManager.Show("Group1.Screen1")这在名称空间中查找(使用反射)Screens.Group1.Screen1一个 View 和一个 ViewModel 并实例化它们。

如何在不耦合的情况下消除魔术字符串Screen1Screen2(我不希望其中的类Screen2使用Screen1命名空间)。我也想要某种屏幕发现(自动完成/智能感知)

或者也许某种方式(自动测试)来验证所有调用ScreenManager.Show是否有效。

更新: 我想出了这个:

public class ScreenNames
{
    public Group1Screens Group1;

    public class Group1Screens
    {
        public ScreenName Screen1;
    }
}

public sealed class ScreenName
{
    private ScreenName() { }
}

public class ScreenManager : IScreenManager
{
    public void Show(Expression<Func<ScreenNames, ScreenName>> x) {}
}

用法:

screenManager.Show(x=>x.Group1.Screen1);

不理想,但我认为违反 DRY 仍然比魔术字符串好。而且我可以自动测试(通过反射)所有调用都是有效的。

4

2 回答 2

3

您不需要 WPF 中的所有 ScreenManager 内容,因为 DataTemplate 引擎可以使用纯标记为您处理这些问题。

您可以使用 ContentPresenter 和一堆 DataTemplate 简单地对应用程序的特定区域进行数据绑定。将该区域绑定到“根”视图模型的属性,并让“根”视图模型实现 INotifyPropertyChanged,以便 WPF 知道您是否更改了该区域中的视图模型。

public class RootViewModel : INotifyPropertyChanged
{
    public object Screen1ViewModel { get; }

    public object Screen2ViewModel { get; }
}

使用 Data 将一个 ContentPresenter 控件绑定到 Screen1ViewModel 属性

<ContentControl Content="{Binding Path=Screen1ViewModel}" />

下一个也是如此。当您需要更改 Screen1 的内容时,您只需从代码中重新分配 Screen1ViewModel,并且由于引发的 PropertyChanged 事件,WPF 将拾取它并将新的 ViewModel 绑定到新的 View。

DataTemplates 可能像这样简单:

<Window.Resources>
    <DataTemplate DataType="{x:Type foo:MyViewModel}">
        <self:MyControl />
    </DataTemplate>
    <DataTemplate DataType="{x:Type foo:MyOtherViewModel}">
        <self:MyOtherControl />
    </DataTemplate>
</Window.Resources>

如果你不熟悉它,这篇关于 WPF 中的 MVVM 的文章是一个很好的介绍。

于 2010-02-10T20:22:25.273 回答
0

最后我使用 T4 代码生成来生成我的ScreenNames类。我通过修改这段代码来做到这一点:Auto generate strong typed navigation class for all user controls in ASP.NET web application

于 2010-02-14T21:49:33.403 回答