【问题标题】:Need help in a wpf application using mef在使用 mef 的 wpf 应用程序中需要帮助
【发布时间】:2012-02-23 13:22:14
【问题描述】:

我正在按照 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; }
} 

这是我的模块之一。服务器窗口模块。这将返回模块 (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()); }
    }
} 

这是我的观点之一。服务器窗口视图。

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.
    }
}          

现在在 Next 按钮功能上,我应该怎么做才能将当前视图替换为 ServerValidationView。

如果有任何困惑,请询问。

谢谢,

【问题讨论】:

  • 发布MainWindow.xaml的相关xaml
  • @jberger 你可以找到它。我已经编辑过了。
  • ContentPresenterContentControl 有时会让我窒息。你试过ContentControl吗?当ListBox.SelectedItem 发生变化时,MainWindowViewModel.UserInterface 属性会受到影响吗?最后,我建议不要在您的IMainModule 中使用UserControl。相反,对于实现IMainModule 的每种类型,在您的视图中定义一个DataTemplate

标签: wpf mvvm mef


【解决方案1】:

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 属性的值控制的。

【讨论】:

    【解决方案2】:

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

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

    这是根据我从http://www.ra-design.at/silverlight/mediaowl/看到的内容进行的疯狂猜测

    【讨论】:

    • 我有一个 wpf 用户控件库项目,其中包含几个视图(用户控件),我想通过按钮事件浏览这些视图。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    相关资源
    最近更新 更多