开发者

Decouple the screens without magic strings

My WPF project will be organised like this :

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

To show the Screen1 from the Screen2 I'll use something like this: ScreenManager.Show("Group1.Screen1") Th开发者_开发知识库is looks (using reflection) in the Screens.Group1.Screen1 namespace for a View and a ViewModel and instantiates them.

How can I eliminate the magic string without coupling Screen1 and Screen2 (I don't want the classes in Screen2 to use the Screen1 namespace). Also I would like some kind of screen discovery (autocompletion/intellisense)

Or maybe some way (automate test) to verify that all calls to ScreenManager.Show are valid.

Update : I came up with this:

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) {}
}

Usage:

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

Not ideal but I suppose violating DRY is still better than magic strings. And I can automatically test (with reflection) that all calls are valid.


You don't need all that ScreenManager stuff in WPF, because the DataTemplate engine can take care of this for you with pure markup.

You can simply databind a particular area of your application with a ContentPresenter and a bunch of DataTemplates. Bind the area to a property of a 'root' ViewModel, and let the 'root' ViewModel implement INotifyPropertyChanged so that WPF knows if you change the ViewModel in that area.

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

    public object Screen2ViewModel { get; }
}

Databind one ContentPresenter control to the Screen1ViewModel property using

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

and similarly for the next one. When you need to change the content of Screen1, you simply re-assign Screen1ViewModel from code, and because of the raised PropertyChanged event, WPF will pick it up and bind the new ViewModel to a new View.

The DataTemplates may be as simple as this:

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

In case you are not familiar with it, this article on MVVM in WPF is an excellent introduction.


Finally I used T4 code generation to generate my ScreenNames class. I did that by adapting this code : Auto generate strong typed navigation class for all user controls in ASP.NET web application

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜