该类型不包括任何可访问的构造函数 WPF - 没有 window 应用程序

The type does not include any accessible constructors WPF - no window application

我正在使用 this 包来创建和使用通知图标,这意味着我的应用程序中没有 Windows 只有 ResourceDictionaryViewModel

在我更改我的构造函数以接受使用 DI 框架的接口之前,一切都运行良好(我正在使用 Autofac PRISM [Prism.Autofac] 的扩展).

如果我重新添加无参数构造函数,一切正常

我什至应该使用 Autofac 是矫枉过正吗?我该如何做 DI?

备注

App.xaml.cs

    public partial class App : Application
    {
        private TaskbarIcon notifyIcon;

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            var bootstrapper = new Bootstrapper();
            bootstrapper.Run();

            notifyIcon = (TaskbarIcon)FindResource("NotifyIcon");          
        }

        protected override void OnExit(ExitEventArgs e)
        {
            notifyIcon.Dispose();
            base.OnExit(e);
        }
    }

App.xaml

  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="NotifyIconResources.xaml" />
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>

NotifyIconResources.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:tb="http://www.hardcodet.net/taskbar"
                    xmlns:local ="clr-namespace:WatchDog"
                    xmlns:interface="clr-namespace:ServiceControllerLibary;assembly=ServiceControllerLibary"
                    >
    <local:ServiceControllerWorkerStatusToIconConverter x:Key="ServiceControllerWorkerStatusToIconConverter"/>

    <ContextMenu x:Shared="false" x:Key="SysTrayMenu">
        <MenuItem Header="Show Window" />
        <MenuItem Header="Hide Window" />
        <Separator />
        <MenuItem Header="Exit" />
    </ContextMenu>  


    <tb:TaskbarIcon x:Key="NotifyIcon"
                    ToolTipText ="{Binding ToolTipText}" DoubleClickCommand="{Binding}"
                    ContextMenu="{StaticResource SysTrayMenu}"
                    IconSource="{Binding ToolTipStatus, 
                    Converter={StaticResource ServiceControllerWorkerStatusToIconConverter}
                    , Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >

        <!-- Original Not Working-->
        <!-- self-assign a data context (could also be done programmatically) -->
        <!--<tb:TaskbarIcon.DataContext>
            <local:NotifyIconViewModel/>
        </tb:TaskbarIcon.DataContext>-->

        <!-- 2nd try Not Working-->
        <tb:TaskbarIcon.DataContext>
            <ObjectDataProvider ObjectType="{x:Type local:NotifyIconViewModel}">
                <ObjectDataProvider.ConstructorParameters>
                    <interface:ServiceControllerWorker />
                </ObjectDataProvider.ConstructorParameters>
            </ObjectDataProvider>
        </tb:TaskbarIcon.DataContext>

    </tb:TaskbarIcon>


</ResourceDictionary>

Bootstrapper.cs

    class Bootstrapper : AutofacBootstrapper 
    {
        protected override void ConfigureContainerBuilder(ContainerBuilder builder)
        {
            base.ConfigureContainerBuilder(builder);

            builder.RegisterType<ServiceControllerWorker>().As<IServiceControllerWorker>().SingleInstance();

        }
    }

NotifyIconViewModel.cs(仅限构造函数)

 public NotifyIconViewModel(IServiceControllerWorker ServiceControllerWorker)
 {    
      _serviceControllerWorker = ServiceControllerWorker;
  }

它不起作用,因为您将 ObjectDataProvider 实例设置为 DataContext

<tb:TaskbarIcon.DataContext>
    <ObjectDataProvider ObjectType="{x:Type local:NotifyIconViewModel}">
        <ObjectDataProvider.ConstructorParameters>
            <interface:ServiceControllerWorker />
        </ObjectDataProvider.ConstructorParameters>
    </ObjectDataProvider>
</tb:TaskbarIcon.DataContext>

而不是 ObjectDataProvider
ResourceDictionary:

中声明提供者
<ResourceDictionary>    
    <ObjectDataProvider x:Key="ViewModelProvider" ObjectType="{x:Type local:NotifyIconViewModel}">
        <ObjectDataProvider.ConstructorParameters>
            <interface:ServiceControllerWorker />
        </ObjectDataProvider.ConstructorParameters>
    </ObjectDataProvider>
</ResourceDictionary>

并将其绑定到 DataContext:

<tb:TaskbarIcon DataContext="{Binding Source={StaticResource ViewModelProvider}}" />

绑定将使提供者实例化提供的实例。

但是由于您是在 ObjectDataProvider 的帮助下创建实例,因此您使 Autofac 容器或依赖项注入变得多余。如果你想使用依赖注入,你必须让 Autofac 创建实例。这需要手动启动应用程序并重写 MainWindowTaskbarIcon 的托管 Window 以使用组合:

public partial class MainWindow : Window
{
    public static readonly DependencyProperty NotifyIconProperty = DependencyProperty.Register(
      "NotifyIcon",
      typeof(TaskbarIcon),
      typeof(Window),
      new PropertyMetadata(default(TaskbarIcon)));

    public TaskbarIcon NotifyIcon { get { return (TaskbarIcon) GetValue(MainWindow.NotifyIconProperty); } set { SetValue(MainWindow.NotifyIconProperty, value); } }

    public MainWindow(TaskbarIcon taskbarIcon, INotifyIconViewModel notifyIconDataContext, IViewModel dataContext)
    {
        this.notifyIcon = taskbarIcon;     
        this.notifyIcon.DataContext = notifyIconDataContext;   
        this.DataContext = dataContext;      
    }
}

在 MainWindow.xaml 中将 属性 绑定到 ContentPresenter:

<Window>
    <ContentPresenter Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=MainWindow}, Path=NotifyIcon} />
</Window>

然后配置Autofac容器:

class Bootstrapper : AutofacBootstrapper 
{
    public Container ConfigureContainerBuilder()
    {
        var builder = new ContainerBuilder();

        builder.RegisterType<ServiceControllerWorker>().As<IServiceControllerWorker>().SingleInstance();
        builder.RegisterType<NotifyIconViewModel>().As<INotifyIconViewModel>().SingleInstance();
        builder.RegisterType<TaskbarIcon>().SingleInstance();
        builder.RegisterType<MainWindow>().SingleInstance();

        return builder.Build();
    }
}

然后bootstrap申请:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        var bootstrapper = new Bootstrapper();
        var container = bootstrapper.ConfigureContainerBuilder();
        Application.Current.MainWindow = container.Resolve<MainWindow>();
        Application.Current.MainWindow.Show();         
    }
}

这样你就摆脱了 ObjectDataProvider,因为你使用的是 Autofac。