Wpf UserControl with its own data context and external dependency property - wpf

I'm trying to create a simple AudioPlayer control multiple reuse in a solution I'm working on. I have seen numerous example in various posts and blogs around the net and from those have created a small control with four buttons.
The xaml is defined thus:
<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>
With fairly simple code in the background;
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
My question quite simply is this. From the code you can see that at present the sound that is being played is hard coded. What I would like to know is wheteher it would be possible to create a dependency property for this control (I presume it would be of type string to represent a path to a sound file but I'm not sure) so that when the control is created in other controls or windows their viewmodels can pass a sound property to it (if that makes sense!).
If it is possible where should I create it in respect of the code snippets shown?
Many thanks

You could create a DP, but it would not work the way users would expect.
For example, if the user were to write
<local:AudioPlayer Media="{Binding SomeString}" />
Then WPF tries to set Media = DataContext.SomeString
But since you have hardcoded DataContext = New AudioPlayerViewModel in the constructor, then the binding will most likely fail because users will be expecting their inherited DataContext to be used by the UserControl, but the hardcoded DataContext will be used instead.
It is always my advice to never hardcode the DataContext property inside of a UserControl. It breaks the entire WPF design pattern of having separate layers for UI and Data.
Either build a UserControl specifically for use with a specific Model or ViewModel being used as the DataContext, such as this :
<!-- Draw anything of type AudioPlayerViewModel with control AudioPlayer -->
<!-- DataContext will automatically set to the AudioPlayerViewModel -->
<DataTemplate DataType="{x:Type local:AudioPlayerViewModel}}">
<local:AudioPlayer />
</DataTemplate>
Or build it with the expectation that the DataContext can be absolutely anything, and DependencyProperites will be used to give the control the data it needs :
<!-- DataContext property can be anything, as long as it as the property MyString -->
<local:AudioPlayer Media="{Binding MyString}" />
The easiest way to get your code to work would probably be
Create the ViewModel as a private property instead of assiging it to the UserControl.DataContext
Bind or set the DataContext of the top level child inside your UserControl to your private property (in your case, the StackPanel)
Adjust the binding for your MediaElement to read from a custom DependencyProperty instead of from StackPanel.DataContext
Something like this :
<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

Related

How to Create a DialogBox to prompt the user for Yes/No option in WPF

I know how to do this on Windows Form App, but I couldn't find anyway of doing so on a WPF App.
How would I present the user a blocking DialogBox with Yes/No option and get/process the response from the user?
Here's an example:
string sMessageBoxText = "Do you want to continue?";
string sCaption = "My Test Application";
MessageBoxButton btnMessageBox = MessageBoxButton.YesNoCancel;
MessageBoxImage icnMessageBox = MessageBoxImage.Warning;
MessageBoxResult rsltMessageBox = MessageBox.Show(sMessageBoxText, sCaption, btnMessageBox, icnMessageBox);
switch (rsltMessageBox)
{
case MessageBoxResult.Yes:
/* ... */
break;
case MessageBoxResult.No:
/* ... */
break;
case MessageBoxResult.Cancel:
/* ... */
break;
}
Please note that while Radu's answer works, you cannot apply WPF styles to the MessageBox.
I took a different approach to this problem.
I created a class to serve as a View Model for my message window and I created a style for how I wanted my window to appear. Later in code I instantiated a new Window, set it's DataContext to an instance of my View Model, and set the Window's Style property to the style I created for the window.
I know it sounds a bit overkill, and I'm not sure how other people go about solving this same issue... but my solution is quite flexible and I'm starting to really like it.
For example, here is Dialog View Model:
Public Class MyDialogViewModel
Public Event Closed()
Public Property Message As String
Public Property Cancel As MyNamespace.RelayCommand
Public Property Close As MyNamespace.RelayCommand
Public Property WasCancelled As Boolean
Public Sub New()
WasCancelled = True
Cancel = New MyNamespace.RelayCommand(AddressOf CancelClicked)
Close = New MyNamespace.RelayCommand(AddressOf CloseClicked)
End Sub
Private Sub CancelClicked()
RaiseEvent Closed()
End Sub
Private Sub CloseClicked()
WasCancelled = False
RaiseEvent Closed()
End Sub
End Class
Here is my style for a basic "message" window:
<Style x:Key="myMessageStyle" TargetType="{x:Type myNameSpace:CustomDialogWindow}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ControlTemplate.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="25"/>
</Style>
</ControlTemplate.Resources>
<Border >
<DockPanel Margin="10,10,0,10">
<TextBlock Text="{Binding Message}" Width="Auto" TextWrapping="WrapWithOverflow" DockPanel.Dock="Top"
Margin="10"
Foreground="{StaticResource MyMessageBoxForegroundColor}"/>
<DockPanel Margin="5,0,0,0" DockPanel.Dock="Bottom">
<Button Content="Ok" Command="{Binding Close}" ></Button>
<Button Content="Cancel" Command="{Binding Cancel}" HorizontalAlignment="Stretch"></Button>
</DockPanel>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My CustomDialogWindow is simply a window with nothing in it:
(XAML)
<Window x:Class="CustomDialogWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CustomDialogWindow"
SizeToContent="WidthAndHeight">
</Window>
And in the CustomDialogWindow I have the following code so that the window closes when the user clicks cancel or ok:
Public Class CustomDialogWindow
Private Sub CustomDialogWindow_DataContextChanged(ByVal sender As Object, ByVal e As System.Windows.DependencyPropertyChangedEventArgs) Handles Me.DataContextChanged
Dim dContext As MyDialogViewModel= TryCast(DataContext, MyDialogViewModel)
If dContext IsNot Nothing Then
AddHandler DirectCast(DataContext, MyDialogViewModel).CloseWindow, AddressOf CloseWindow
End If
End Sub
Private Sub CloseWindow()
Me.Close()
End Sub
End Class
Now when I need to use the window I just instantiate a new CustomDialogWindow, set it's DataContext to a new instance of the DialogViewModel class, and set it's style to the "myMessageStyle":
Dim cdw As New CustomDialogWindow
Dim dvm As New DialogViewModel
dvm.Message = "Hello World!"
cdw.DataContext = dvm
cdw.ShowDialog()
If dvm.WasCancelled = False Then
'....'
End If
The reason why I like this approach is because I inherit from the MyDialogViewModel and provide more properties so that, for instance, I can display a bunch of options for the user to choose from. I just supply custom styles for each type of window I want to display (making sure to bind the appropriate properties). Like I said, it's very flexible and pretty simple to implement.
Cheers!
-Frinny

WPF Button in DataGrid/ListBox

I've encountered a problem when converting a WPF project from vs2008 to vs2010.
I have a DataGrid that contains a ListBox. Each ListBoxItem has a Label and a Button. After converting to vs2010 the button no longer renders but crashes the app as soon as it comes into view. (Ie. the app loads but when the ListBox is created I get a NullReferenceException. What does work though is to remove the click event from the button and then it renders fine :) Same type of setup with Button within ListBoxItem also works when not inside a DataGrid. The content of ListBox obviously is meant to be dynamic but when working with a static collection I get the same error. Also removing the CommandParam does not help at all. Any pointers most welcome.
Code:
<DataGrid x:Name="DgTest" AutoGenerateColumns="false">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<ListBox ItemsSource="{Binding ItemList}">
<ListBox.ItemTemplate>
<DataTemplate >
<StackPanel Style="{StaticResource hzp}">
<Label />
<Button Click="Button_Click" Content="TestButton"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Code-behind:
Imports System.Collections.ObjectModel
Class MainWindow
Public TestList As New ObservableCollection(Of TestClass)
Private Sub MainWindow_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
DgTest.ItemsSource = TestList
TestList.Add(New TestClass(0))
TestList.Add(New TestClass(1))
End Sub
Public Class TestClass
Private _ItemList As New List(Of String)
Private _id As Integer
Public Property ItemList() As List(Of String)
Get
Return _ItemList
End Get
Set(ByVal value As List(Of String))
_ItemList = value
End Set
End Property
Public Property Id() As Integer
Get
Return _id
End Get
Set(ByVal value As Integer)
_id = value
End Set
End Property
Public Sub New(ByVal id As Integer)
_ItemList.Add("String1")
_id = id
End Sub
End Class
Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
End Sub
End Class
And in App Resources:
<Style TargetType="StackPanel" x:Key="hzp">
<Setter Property="Orientation" Value="Horizontal"/>
<Setter Property="Background" Value="Orange"/>
</Style>
Now here's the strange thing. If the Stackpanel Style is removed, the button will work. If the Click event for the button is removed, it will load normally.
Seems like your event handler is gone from the code-behind file, check that first. Comment if that is not the case.
I believe I have found the answer to my own question. In the ListBox bound to an ObservableCollection all Styles must be DynamicResource. Using StaticResource worked well in 3.5 but not 4! Took a few hours of randomly testing everything to find this. Case closed

Setting content of TextBlock and text of HyperlinkButton in silverlight custom control

I am trying to create a custom control that will display a hyperlink button with some text below the link. The idea is to have urgent messages show up on a screen of a Silverlight page. From what I have read, I thought that I should be able to create a new control and then create some dependancy properties and bind the dynamic parts of the component pieces to them in order to allow me to add multiple instances of the custom control to my Silverlight project. Here is my XAML that defines the control
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="WhatsNew.UrgentStoryGridControl"
d:DesignWidth="608" d:DesignHeight="65" Background="White">
<UserControl.Resources>
<Style x:Key="WhatsNewTitleStyle" TargetType="HyperlinkButton">
Removed for Brevity
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Height="65" Margin="0" VerticalAlignment="Bottom" Background="White">
<StackPanel>
<HyperlinkButton Style="{StaticResource WhatsNewTitleStyle}" Content="{Binding linkText}" HorizontalAlignment="Left" VerticalAlignment="Top" NavigateUri="{Binding linkURI}" Foreground="Red"/>
<TextBlock Style="{StaticResource WhatsNewTextStyle}" Text="{Binding storyText}" Margin="0,13,0,0" d:LayoutOverrides="Height"/>
</StackPanel>
</Grid>
In the code behind, I have created three dependancy properties
Partial Public Class UrgentStoryGridControl
Inherits UserControl
Public Shared linkTextProperty As DependencyProperty = DependencyProperty.Register("linkText", GetType(String), GetType(UrgentStoryGridControl), New PropertyMetadata("Link Text"))
Public Shared linkURIProperty As DependencyProperty = DependencyProperty.Register("linkURI", GetType(String), GetType(UrgentStoryGridControl), New PropertyMetadata("link.html"))
Public Shared storyTextProperty As DependencyProperty = DependencyProperty.Register("storyText", GetType(String), GetType(UrgentStoryGridControl), New PropertyMetadata("Story Text"))
Public Property linkText() As String
Get
Return GetValue(linkTextProperty)
End Get
Set(ByVal value As String)
SetValue(linkTextProperty, value)
End Set
End Property
Public Property linkURI() As String
Get
Return GetValue(linkURIProperty)
End Get
Set(ByVal value As String)
SetValue(linkURIProperty, value)
End Set
End Property
Public Property storyText As String
Get
Return GetValue(storyTextProperty)
End Get
Set(ByVal value As String)
SetValue(storyTextProperty, value)
End Set
End Property
End Class
When I place this control on my Silverlight project using Expression Blend, I see the three properties listed in the Miscellaneous section of the properties window as I would expect. The values from the PropertyMetadata are populated as the default values for these properties. Here is the code from my Silverlight project where I leave the default values alone:
<local:UrgentStoryGridControl x:Name="urgentStory" Height="65" />
Here is the code where I try to set the values to something:
<local:UrgentStoryGridControl x:Name="urgentStory" Height="65" linkText="Test Link Text" linkURI="testpage.html" storyText="Sample Story Text" />
Either way I attempt to use the control, I'm not getting anything displayed when I launch the application. I figure that I'm missing something small but after having spent a lot of time today researching this, I'm not finding anything that would indicate what I'm missing or doing wrong.
You need to set the DataContext in your custom UserControl or else your bindings won't work.
In your UrgentStoryGridControl's constructor, you should be able to set Me.DataContext = Me

WPF DataGrid and Avalon TimePicker binding is not working

I'm using a the WPF DataGrid from the wpf toolkit and a TimePicker from AvalonControlsLibrary to insert a collection of TimeSpans. My problem is that bindings are not working inside the DataGrid, and I have no clue of why this isn't working.
Here is my setup:
I have the following XAML:
<Window x:Class="TestMainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:wpf="http://schemas.microsoft.com/wpf/2008/toolkit" xmlns:a="http://schemas.AvalonControls/AvalonControlsLibrary/Controls" SizeToContent="WidthAndHeight" MinHeight="250" MinWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<GroupBox Grid.Row="0">
<GroupBox.Header>
Testing it:
</GroupBox.Header>
<wpf:DataGrid ItemsSource="{Binding Path=TestSpans}" AutoGenerateColumns="False">
<wpf:DataGrid.Columns>
<wpf:DataGridTemplateColumn Header="Start">
<wpf:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<a:TimePicker SelectedTime="{Binding Path=Span, Mode=TwoWay}" />
</DataTemplate>
</wpf:DataGridTemplateColumn.CellEditingTemplate>
<wpf:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Span}" />
</DataTemplate>
</wpf:DataGridTemplateColumn.CellTemplate>
</wpf:DataGridTemplateColumn>
</wpf:DataGrid.Columns>
</wpf:DataGrid>
</GroupBox>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="1">
<a:TimePicker SelectedTime="{Binding Path=SelectedTime, Mode=TwoWay}" />
</StackPanel>
</Grid>
And this is my ViewModel:
Imports System.Collections.ObjectModel
Public Class TestMainWindowViewModel
Private _selectedTime As TimeSpan = DateTime.Now.TimeOfDay
Public Property SelectedTime() As TimeSpan
Get
Return _selectedTime
End Get
Set(ByVal value As TimeSpan)
_selectedTime = value
End Set
End Property
Private _testSpans As ObservableCollection(Of TimeSpanContainer) = New ObservableCollection(Of TimeSpanContainer)
Public Property TestSpans() As ObservableCollection(Of TimeSpanContainer)
Get
Return _testSpans
End Get
Set(ByVal value As ObservableCollection(Of TimeSpanContainer))
_testSpans = value
End Set
End Property
Public Sub New()
_testSpans.Add(DateTime.Now.TimeOfDay)
_testSpans.Add(DateTime.Now.TimeOfDay)
_testSpans.Add(DateTime.Now.TimeOfDay)
End Sub
End Class
Public Class TimeSpanContainer
Private _span As TimeSpan
Public Property Span() As TimeSpan
Get
Return _span
End Get
Set(ByVal value As TimeSpan)
_span = value
End Set
End Property
Public Sub New(ByVal t As TimeSpan)
_span = t
End Sub
End Class
I'm starting this window in application.xaml.vb like this:
Class Application
' Application-level events, such as Startup, Exit, and DispatcherUnhandledException
' can be handled in this file.
Protected Overrides Sub OnStartup(ByVal e As System.Windows.StartupEventArgs)
MyBase.OnStartup(e)
Dim window As TestMainWindow = New TestMainWindow
window.DataContext = New TestMainWindowViewModel()
window.Show()
End Sub
End Class
EDIT 1: I forgot to mention that the binding to SelectedTime TimeSpan works as expected. The problem are the bindings inside the DataGrid.
EDIT 2: Changed example a little bit to show the problem better.
What do you mean by your bindings aren't working? Are you getting no value in the timepicker control when you attempt to edit the value?
Edit:
Ok, I was having this same issue yesterday and I think there is 2 parts to the issue.
If there is no value appearing in the TimePicker control when you switch to edit mode then there is probably a binding issue with the control.
The binding to the underlying value I found to be an issue with using the DataGridTemplateColumn. Basically the grid doesnt handle your databinding back using the same mechanisms of regular bound columns. What it means is you need to perform the following binding on your controls within the column:
SelectedTime="{Binding Span, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
This will fix the binding back to the underlying object. However if there is still an issue with the control it may not help you much. Sorry but I haven't used AvalonControlsLibrary so not sure if there is a potential problem there. Fixing step 2 solved my issues.
Cheers
-Leigh
I know this is an old question, but I where playing with this exact control having the exact same issue. I looked in the TimePicker class of AvalonControlsLibrary and the constructor looks like this
/// <summary>
/// Default constructor
/// </summary>
public TimePicker()
{
SelectedTime = DateTime.Now.TimeOfDay;
}
Removing the line setting the SelectedTime restored the databinding behaviour for me making your posted example work as intended.

wpf command custom control binding xaml

i'm building a Videoplayer custom control (Project called WpfCustomControlLibrary1) and want to add a Load Command.
This is what i have added in my class to get this Command:
Public Class VideoPlayer
Inherits Control
...
Public Shared ReadOnly LoadCommad As RoutedUICommand
....
Shared Sub New()
'This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
'This style is defined in Themes\Generic.xaml
DefaultStyleKeyProperty.OverrideMetadata(GetType(VideoPlayer), New FrameworkPropertyMetadata(GetType(VideoPlayer)))
LoadCommad = New RoutedUICommand("Load", "Load Video", GetType(VideoPlayer))
CommandManager.RegisterClassCommandBinding(GetType(VideoPlayer), New CommandBinding(LoadCommad, AddressOf OnLoadExecuted))
End Sub
...
And this is how i call it from my XAML:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCustomControlLibrary1">
.....
<Button Command="local:VideoPlayer.LoadCommand"
DockPanel.Dock="Right" Margin="0 5 5 0"
Width="30" HorizontalAlignment="Left"
Content="..." />
.....
But when i add this Usercontrol to a new Project like this:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:bibli="clr-namespace:EigeneControllsBibli;assembly=EigeneControllsBibli"
xmlns:uc="clr-namespace:WpfCustomControlLibrary1;assembly=WpfCustomControlLibrary1"
Title="Window1" Height="442" Width="804">
<Grid>
<uc:VideoPlayer Source="C:\Users\Public\Videos\Sample Videos\Bear.wmv" Margin="0,106,369,0"></uc:VideoPlayer>
</Grid>
i get an error that he cant convert the string in the Attribute "Command" into an Object of the Type "System.Windows.Input.ICommand
Does somebody see whats going wrong?
Thanks for helping,
Nico
you have a spelling-mistake:
LoadCommad = New RoutedUICommand("Load", "Load Video", GetType(VideoPlayer))
should be
LoadCommand = New RoutedUICommand("Load", "Load Video", GetType(VideoPlayer))
I don't know if this produces the error, but perhaps.
I think what you want to do is declare LoadCommand as an instance rather than Shared variable, so:
Public Class VideoPlayer
Inherits Control
...
Private ReadOnly m_LoadCommand As RoutedUICommand
....
Shared Sub New()
'This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
'This style is defined in Themes\Generic.xaml
DefaultStyleKeyProperty.OverrideMetadata(GetType(VideoPlayer), New FrameworkPropertyMetadata(GetType(VideoPlayer)))
End Sub
Sub New()
m_LoadCommand = New RoutedUICommand("Load", "Load Video", GetType(VideoPlayer))
End Sub
Public Property LoadCommand As ICommand
Get
Return m_LoadCommand
End Get
End Property
...
Then you bind the Button.Command property in the XAML, so:
<StackPanel>
<uc:VideoPlayer x:Name="myPlayer" Source="C:\Users\Public\Videos\Sample Videos\Bear.wmv" Margin="0,106,369,0"></uc:VideoPlayer>
<Button Command="{Binding ElementName=myPlayer, Path=LoadCommand"
Width="30"
Content="..." />
</StackPanel>

Resources