在使用mef的wpf应用程序中需要帮助

时间:2012-02-23 13:22:14

标签: wpf mvvm mef

我正在使用MVVM模式在wpf中创建一个应用程序。我需要在其中添加MEF。

这是我的程序的基本架构。

我有一个主项目MefApplication。这只有一个视图MainWindow.xaml。它包含一个列表框和一个用户控件。应用程序运行时,它会加载模块并将其列在列表框中。单击模块会导致在用户控件中显示模块。

现在对于模块,它是一个WPF用户控件库。现在这个模块将包含不同的视图。一个视图将有一个按钮,用于导航到模块中的其他视图。

现在我已加载模块并将其列出。单击模块会导致显示模块的第一个屏幕。但是,当我单击模块视图上的下一个按钮时,没有任何反应。我不知道如何进入下一个视图。以下是我的代码。谁能告诉我哪里出错了?

MainWindow.xaml

<Window x:Class="MefApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="40*"/>
        <ColumnDefinition Width="80*"/>
    </Grid.ColumnDefinitions>
    <ListBox x:Name="listBox" Grid.Column="0" 
    ItemsSource="{Binding Modules}" SelectedItem="{Binding SelectedModule, Mode=TwoWay}" >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding ModuleName}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <ContentPresenter x:Name="contentPresenter" Grid.Column="1" Content="{Binding UserInterface}"/>
</Grid>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainWindowViewModel();
    }
}

MainWindowViewModel.cs

class MainWindowViewModel : INotifyPropertyChanged
{
    #region NotifyOfPropertyChanged
    #endregion

    private string _path = "Path to Modules Dll Folder"; 
    public MainWindowViewModel()
    {
        Modules = GetModules(_path);
        SelectedModule = Modules[0];
    }

    public List<IMainModule> GetModules(string path)
    {
        var directoryCatalog = new DirectoryCatalog(path);
        var container = new CompositionContainer(directoryCatalog);
        var modules = container.GetExportedValues<IMainModule>().ToList();
        return modules;
    }

    private IMainModule selectedModule;

    public List<IMainModule> Modules { get; set; }

    public IMainModule SelectedModule
    {
        get { return selectedModule; }
        set
        {
            if (value != selectedModule)
            {
                selectedModule = value;
                NotifyOfPropertyChange("SelectedModule");
                NotifyOfPropertyChange("UserInterface");
            }
        }
    }

    public UserControl UserInterface
    {
        get
        {
            if (SelectedModule == null)
                return null;
            return SelectedModule.UserInterface;
        }
    }
} 

这是模块界面。它包含模块名称及其起始视图。

public interface IMainModule
{
    string Name { get; }
    UserControl UserInterface { get; }
} 

这是我的模块之一。 ServerWindowModule。这将返回模块(ServerWindow)中我的一个视图的UserControl。

[Export(typeof(IMainModule))]
class ServerWindowModule : IMainModule
{
    public string Name
    {
        get { return "Server Module"; }
    }

    public UserControl _userInterface { get; set; }
    public UserControl UserInterface
    {
        get { return _userInterface ?? (_userInterface = new ServerWindowView()); }
    }
} 

这是我的观点之一。 ServerWindowView。

public partial class ServerWindowView : UserControl
{
    public ServerWindowView()
    {
        InitializeComponent();
        DataContext = new ServerWindowViewModel();
    }
} 

现在这里是ServerWindowViewModel的ViewModel。

publicclassServerWindowViewModel : INotifyPropertyChanged
{
    #region NotifyOfPropertyChanged
    #endregionpublic ServerWindowViewModel()
    {
        LabelText = "Constructor set this.";
    }

    publicstring LabelText { get; set; }

    privateICommand _nextCommand;
    publicICommand NextCommand
    {
        get { return _nextCommand ?? (_nextCommand = newRelayCommand(NextFunction)); }
    }

    public void NextFunction()
    {
        LabelText = "Button set this.";
        NotifyOfPropertyChange("LabelText");
        // TODO: Navigate to ServerValidation View
        // Here i want to go to my next view(ServerValidationView). What should I write here.
    }
}          

现在启用“下一步”按钮功能,我该怎么做才能将当前视图替换为ServerValidationView。

如果有任何混淆,请询问。

谢谢,

2 个答案:

答案 0 :(得分:0)

我目前正在做类似的事情。我不确定这是否是处理它的正确方法,但我的设计是每个模块都有自己的Shell。

例如,服务器窗口的第一个视图是具有内容呈现器的Shell。要更改模块中的视图,我将更改模块中演示者的内容。

根据我从http://www.ra-design.at/silverlight/mediaowl/

看到的内容,这是一个疯狂的猜测

答案 1 :(得分:0)

Caliburn.Micro可以帮助您解决这个问题或Rob Eisenberg在Mix上提出的框架。它使用依赖属性

public static class View
{
    public static DependencyProperty ModelProperty =
        DependencyProperty.RegisterAttached(
            "Model",
            typeof(object),
            typeof(View),
            new PropertyMetadata(ModelChanged)
            );

    public static void SetModel(DependencyObject d, object value)
    {
        d.SetValue(ModelProperty, value);
    }

    public static object GetModel(DependencyObject d)
    {
        return d.GetValue(ModelProperty);
    }

    public static void ModelChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        if (args.NewValue == null || args.NewValue == args.OldValue)
            return;

        var vm = args.NewValue as IYourModuleProvidingUI;
        var view = vm.UserInterface;

        ((ContentControl)sender).Content = view;
    }
}

使用

<ContentControl Framework:View.Model="{Binding SelectedModule}" Padding="2,0,0,2"/>

SelectedViewModel是在其值已更改时引发INotifyPropertyChanged事件的属性。因此,显示的内容由SelectedModule属性的值控制。