【问题标题】:Playing MediaPlayer from standard lib从标准库播放 MediaPlayer
【发布时间】:2021-04-21 04:01:43
【问题描述】:

从我的 .NETStandard 2.1 库中,我无权访问 MediaPlayer 类。 当事件发生在它的一个方法中时,来自同一个库的服务应该播放一个 mp3 文件

我的主要项目是一个 .NET5 WPF,这个小代码在单独测试它时运行良好:

private void PlayAlert()
{
    MediaPlayer mediaPlayer = new MediaPlayer();
    mediaPlayer.Open(new Uri("alert.mp3", UriKind.Relative));
    mediaPlayer.Play();
} 

您如何干净利落地将我的库与仅在此处有效的私有方法连接起来?

谢谢!

【问题讨论】:

    标签: c# wpf class-library .net-5


    【解决方案1】:

    您可以在您的类库中创建一个ISoundPlayer 接口,并在您需要的任何地方将其作为依赖项传递给类的构造函数。

    然后在您的 Wpf 应用程序中,在 MySoundPlayer 类中实现该接口,并且每当您想要实例化依赖于 ISoundPlayer 的类库中的其中一个类时,将 MySoundPlayer 传递给它们。

    还有一些其他可能的解决方案,如果您有兴趣了解它们,请阅读答案底部关于控制反转的注释。

    示例

    以下示例不使用任何 DI 框架,而是创建了一个类库,该类库具有一个 MyClass,该类依赖于一个名为 ISoundPlayer 的接口。然后在另一个项目中,一个 Wpf 应用程序,实现 ISoundPlayer,实例化 MyClass 并将 ISoundPlayer 的实现传递给它。您可以使用 DI 库(不在本 q/a 范围内)使用相同的功能。

    按照以下步骤操作:

    1. 创建一个 WPF 应用程序,MyWpfApp

    2. 创建一个 .NET 标准类库项目,MyClassLibrary

    3. 在你的类库中添加一个ISoundPlayer 接口:

      namespace MyClassLibrary
      {
          public interface ISoundPlayer
          {
              void PlaySound();
          }
      }
      
    4. 在构造函数中添加一个获取ISoundPlayer接口的类:

      using System;
      
      namespace MyClassLibrary
      {
          public class MyCLass
          {
              ISoundPlayer soundPlayer;
              public MyCLass(ISoundPlayer soundPlayer)
              {
                  this.soundPlayer = soundPlayer ??
                      throw new ArgumentNullException(nameof(soundPlayer));
              }
              public void DoSomething()
              {
                  //Do something
                  soundPlayer.PlaySound();
              }
          }
      }
      
    5. 将 MyClassLibrary 的引用添加到您的 MyWpfApp。

    6. 创建一个实现 ISoundPlayerInterface 的 MySoundPlayer 类:

      using MyClassLibrary;
      using System;
      using System.Windows.Media;
      
      namespace MyWpfApp
      {
          public class MySoundPlayer : ISoundPlayer
          {
              public void PlaySound()
              {
                  //var player = new MediaPlayer();
                  //player.Open(new Uri("alert.mp3"));
                  //player.Play();
                  //or simply
                  System.Media.SystemSounds.Beep.Play();
              }
          }
      }
      
    7. 在主窗口上放置一个按钮并处理其点击事件,实例化 MyClass 并将 MySoundPlayer 的实例传递给它。

      private void button_Click(object sender, RoutedEventArgs e)
      {
          var myClass = new MyClassLibrary.MyCLass(new MySoundPlayer());
          myClass.DoSomething();
      }
      

    注意

    要实现Inversion of Control,您可以考虑以下选项:

    • 依赖注入:您可以依赖具有 PlaySound 方法的 ISoundPlayer 接口并将此依赖注入到您的库中。
    • 事件:您可以在库中引发事件,让消费者订阅该事件并播放声音。
    • 委托:您可能想要注入一个委托(作为属性或通过构造函数)并在您的库中使用该委托。

    【讨论】:

    • 你能举个例子吗?我已经在使用 ioc 但我所有的接口和代码都在 lib 中,所以 MediaPlayer 也不能在那里
    • 我编辑了答案并删除了其余示例,它超出了答案的范围,对于未来的读者来说太长了。
    • 如果您对上一版本仍有兴趣,可以find it here
    • 感谢您提供的示例,但我不想从 WPF 端触发事件。假设只有我的标准库中的后台服务会在需要时执行声音。所以没有点击按钮,没有来自 WPF 的事件。我想我必须从后台服务发送一个事件并将一些 WPF 处理程序加载到服务中,但这就是我不知道如何干净地做到这一点。可能是可观察的模式?
    • 没什么区别。只需传入依赖项并在后台服务中使用它。后台服务只不过是一个类,它具有像 DoSomething 这样的方法,它们在某个时间点以某种方式运行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    • 2012-01-06
    • 1970-01-01
    相关资源
    最近更新 更多