簡體   English   中英

WPF UserControl具有自己的數據上下文和外部依賴項屬性

[英]Wpf UserControl with its own data context and external dependency property

我正在嘗試創建一個簡單的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

我的問題很簡單是這個。 從代碼中可以看到,目前正在播放的聲音已經過硬編碼。 我想知道的是,有可能為此控件創建一個依賴項屬性(我想它應該是字符串類型,代表聲音文件的路徑,但我不確定),以便在控件處於在其他控件或窗口中創建的它們的視圖模型可以向其傳遞聲音屬性(如果有道理!)。 如果有可能,我應該根據所示的代碼片段在何處創建它?

非常感謝

您可以創建一個DP,但是它不能像用戶期望的那樣工作。

例如,如果用戶要寫

<local:AudioPlayer Media="{Binding SomeString}" />

然后WPF嘗試設置Media = DataContext.SomeString

但是,由於在構造函數中已對DataContext = New AudioPlayerViewModel進行了硬編碼,因此綁定很可能會失敗,因為用戶希望其繼承的DataContext被UserControl使用,但是將使用硬編碼的DataContext。


始終建議不要在UserControl內部對DataContext屬性進行硬編碼。 它打破了將UI和數據具有單獨的圖層的整個WPF設計模式。

構建專門用於與用作DataContext的特定Model或ViewModel一起使用的UserControl,例如:

<!-- 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}" />

使代碼正常工作的最簡單方法可能是

  • 創建ViewModel作為私有屬性,而不是將其輔助到UserControl.DataContext
  • 將UserControl中頂級子級的DataContext綁定或設置為私有屬性(在您的情況下為StackPanel)
  • 調整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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM