我正在尝试在我正在处理的解决方案中创建一个简单的AudioPlayer控件多次重用。我在网上的各种帖子和博客中看到了很多例子,并且从那些创建了一个带有四个按钮的小控件。
因此定义了xaml:
<UserControl x:Class="AudioPlayer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="150">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="10,0,0,0" />
</Style>
</StackPanel.Resources>
<MediaElement Name="media" Source="{Binding Source}" LoadedBehavior="{Binding LoadedBehavior}"/>
<Button Width="24" Height="24" x:Name="Repeat" Background="Transparent" BorderBrush="Transparent">
<Image Source="Images/button_blue_repeat.png" ToolTip="Repeat"/>
</Button>
<Button Width="24" Height="24" x:Name="Play" Background="Transparent" BorderBrush="Transparent">
<Image Source="Images/button_blue_play.png" ToolTip="Play"/>
</Button>
<Button Width="24" Height="24" x:Name="Pause" Background="Transparent" BorderBrush="Transparent">
<Image Source="Images/button_blue_pause.png" ToolTip="Pause"/>
</Button>
<Button Width="24" Height="24" x:Name="Stop" Background="Transparent" BorderBrush="Transparent">
<Image Source="Images/button_blue_stop.png" ToolTip="Stop"/>
</Button>
</StackPanel>
在后台使用相当简单的代码;
Public Class AudioPlayer
Public Sub New()
InitializeComponent()
DataContext = New AudioPlayerViewModel With {.MediaElement = media, .Source = "bag1.mp3", .LoadedBehavior = MediaState.Manual, .CanCommandExecute = True}
End Sub
End Class
Public Class AudioPlayerViewModel
Inherits DependencyObject
Public Sub New()
Me.MediaCommand = New MediaElementCommand(Me)
End Sub
Public Property MediaElement() As MediaElement
Public Property Source() As String
Public Property LoadedBehavior() As MediaState
Public Property CanCommandExecute() As Boolean
Public Property MediaCommand() As ICommand
End Class
Public Class MediaElementCommand
Implements ICommand
Private vm As AudioPlayerViewModel
Public Sub New(ByVal vm As AudioPlayerViewModel)
Me.vm = vm
End Sub
Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute
Return vm.CanCommandExecute
End Function
Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
AddHandler(ByVal value As EventHandler)
AddHandler CommandManager.RequerySuggested, value
End AddHandler
RemoveHandler(ByVal value As EventHandler)
RemoveHandler CommandManager.RequerySuggested, value
End RemoveHandler
RaiseEvent(ByVal sender As System.Object, ByVal e As System.EventArgs)
End RaiseEvent
End Event
Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
Dim action As String = DirectCast(parameter, String)
Select Case action.ToLower()
Case "play"
vm.MediaElement.Position = TimeSpan.Zero
vm.MediaElement.Play()
Case "stop"
vm.MediaElement.Stop()
Case "pause"
vm.MediaElement.Pause()
Case "resume"
vm.MediaElement.Play()
Case Else
Throw New NotSupportedException(String.Format("Unknown media action {0}", action))
End Select
End Sub
End Class
我的问题很简单就是这个。从代码中可以看出,目前播放的声音是硬编码的。我想知道的是,有可能为这个控件创建一个依赖属性(我假设它是类型字符串来表示声音文件的路径,但我不确定)所以当控件是在其他控件或窗口中创建的视图模型可以将声音属性传递给它(如果这有意义!)。 如果有可能我应该在哪里创建它显示的代码片段?
非常感谢
答案 0 :(得分:1)
您可以创建一个DP,但它不会像用户期望的那样工作。
例如,如果用户要写
<local:AudioPlayer Media="{Binding SomeString}" />
然后WPF尝试设置Media = DataContext.SomeString
但是由于你在构造函数中有硬编码DataContext = New AudioPlayerViewModel
,因此绑定很可能会失败,因为用户期望UserControl使用它们继承的DataContext,但是将使用硬编码的DataContext。
我总是建议从不对UserControl中的DataContext
属性进行硬编码。它打破了整个WPF设计模式,即为UI和数据提供单独的层。
构建专门用于特定模型的UserControl或用作DataContext
的ViewModel,例如:
<!-- Draw anything of type AudioPlayerViewModel with control AudioPlayer -->
<!-- DataContext will automatically set to the AudioPlayerViewModel -->
<DataTemplate DataType="{x:Type local:AudioPlayerViewModel}}">
<local:AudioPlayer />
</DataTemplate>
或者构建它,期望DataContext
可以绝对是任何东西,并且DependencyProperites将用于为控件提供所需的数据:
<!-- DataContext property can be anything, as long as it as the property MyString -->
<local:AudioPlayer Media="{Binding MyString}" />
让代码工作的最简单方法可能是
MediaElement
的绑定,以便从自定义DependencyProperty而不是StackPanel.DataContext
这样的事情:
<UserControl x:Name="MyAudioPlayer" ...>
<StackPanel x:Name="AudioPlayerRoot">
...
<MediaElement Source="{Binding ElementName=MyAudioPlayer, Path=MediaDependecyProperty}" ... />
...
</StackPanel>
</UserControl>
Public Sub New()
InitializeComponent()
AudioPlayerRoot.DataContext = New AudioPlayerViewModel ...
End Sub