Creating audio player on WPF using NAudio. Binding doesn't work - c#

I am creating my audio player on WPF using NAudio.
I am adding a slider that will be scroll the song.
XAML:
<Slider Height="30"
Value="{Binding Path=MediaReader.Position, Mode=TwoWay}"
Maximum="{Binding Path=MediaReader.Length, Mode=OneWay}"/>
Note. MediaReader - it's a property that returns the object of type MediaFoundationReader:
MediaFoundationReader mediaReader;
public MediaFoundationReader MediaReader => mediaReader;
Problem: while the song is plaing the slider property Value doesn't change! But by scrolling the thumb of the slider the property Position of the MediaReader changes.
Why does it work so and how can I solve that?

Just take a look to this tutorial:
https://www.pluralsight.com/guides/building-a-wpf-media-player-using-naudio
The author uses also a slider control and binds the current track position, e.g.:
<Slider Grid.Column="0" Minimum="0" Maximum="{Binding CurrentTrackLenght, Mode=OneWay}" Value="{Binding CurrentTrackPosition, Mode=TwoWay}" x:Name="SeekbarControl" VerticalAlignment="Center">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding TrackControlMouseDownCommand}"></i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseUp">
<i:InvokeCommandAction Command="{Binding TrackControlMouseUpCommand}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Slider>
public double CurrentTrackPosition
{
get { return _currentTrackPosition; }
set
{
if (value.Equals(_currentTrackPosition)) return;
_currentTrackPosition = value;
OnPropertyChanged(nameof(CurrentTrackPosition));
}
}
I think you can get the idea behind this...

Related

WPF button binding

I've got the application with ListView which I populate with images names, weights, etc. and inside one of the cells should be 2 buttons or labels to user interaction. I've searched and tried what I find on the web, but nothing helps.
<StackPanel Orientation="Horizontal">
<Grid>
<Button
Grid.Row="0"
Command="{Binding ShowImageCommand}"
Content="Show">
</Button>
</Grid>
<Grid>
<Button Content="Annotate"
CommandParameter="{Binding}"
Command="{Binding DataContext.ShowImageCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type local:MainWindow}}}" />
</Grid>
Neither option for Annotate button or Show works. I've tried to do it like a label, but also no success.
<Label Content="Show" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown" >
<i:InvokeCommandAction Command="{Binding ShowImageCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
Here is how it looks like in class:
public MainViewModel()
{
ShowImageCommand = new RelayCommand(ShowImageMethod);
}
public ICommand ShowImageCommand { get; set; }
public void ShowImageMethod()
{
RaisePropertyChanged("ShowImageCommand");
Messenger.Default.Send<NotificationMessage>(new NotificationMessage("It's fine"));
}
I'm new to C# and MVVM pattern, so mostly I just copy-paste code from Stack and trying to make it work. Other buttons on the grid, for example, to add images to ListView are implemented in the same way, but everything works for those. Please give me some hints.
Is your viewmodel bind to your view?
DataContext = new MainViewModel();
or
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
Like Isaudon said I haven't had
DataContext = new MainViewModel();
After I added this to MainWindow.xaml.cs is implementation works out:
<Button Content="Annotate"
CommandParameter="{Binding}"
Command="{Binding DataContext.ShowImageCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type local:MainWindow}}}" />

MVVM How bind MouseLeftButtonDown and MouseLeftButtonUp in Canvas

Im trying to add new child(circle) to my Canvas after user click on it. And i want to change position of circles while draging them.
I want to do it with MVVM but dont know how catch these events in ViewModel.
I need a MouseLeftButtonUp/Down
I've tried wih System.Windows.Interactivity but it didnt helped.
My only idea is to add invisible button and do easy binding Command="{Binding Method}", but it still wont solve my problem, and certainly its not a best option
This in my XAML code (part of it)
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<Canvas x:Name="DrawableCanvas" HorizontalAlignment="Left" Height="{Binding ElementName=GridContainer, Path=ActualHeight}" VerticalAlignment="Top" Width="{Binding ElementName=GridContainer, Path=ActualWidth}" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding CanvasActionCommand}" x:Name="interactifityFix2">
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Canvas>
Add this namespace in your XAML:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
then you can add an interaction trigger wich will merge the event with an icommand in your viemodel like so:
<Ellipse>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding MouseDownCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Ellipse>

How Mode=TwoWay bindings submit the update?

The textbox is bound to a ViewModel and if its content has been updated the ViewModel would submit the update to a source(normally db).
The XAML side should be like this.
<TextBox Grid.Column="1" Grid.Row="1"
Text="{Binding Path=LowVoltage, StringFormat={}{0:N3}, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
Meanwhile, in the ViewModel, is it a good choice to do update like this?
private float lowVoltage;
public float LowVoltage
{
get { return this.lowVoltage; }
set
{
if (this.lowVoltage != value)
{
this.lowVoltage = value;
**//dbContext.Submit(); --here**
this.RaisePropertyChanged("LowVoltage");
}
}
}
I wouldn't choose to make database operations inside a property setter, better work with Commands, like access the ViewModel in the behind code LostFocus event handler and execute it or use EventTrigger in XAML.
<Grid xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SomeEvent">
<i:InvokeCommandAction Command="{Binding Path=SomeCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>

RelativeSource binding can't find Frame ancestor

I'm trying to pass as a CommandParameter the actual Frame object to which I'm applying the Command
XAML
<Frame NavigationUIVisibility="Hidden" Source="{Binding TargetContentPage}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="ContentRendered">
<command:EventToCommand Command="{Binding ContentRendered}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Frame}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Frame>
C#
public RelayCommand<Frame> ContentRendered
{
get
{
return new RelayCommand<Frame>(frame => frame.RemoveBackEntry());
}
}
When running, a NullReferenceException is raised saying frame is null.
What is possibly wrong in the code above ?
There is no ancestor/descendent relation between Frame and EventToCommand. Use an ElementName binding instead:
<Frame x:Name="frame" ...>
<i:Interaction.Triggers>
<i:EventTrigger EventName="ContentRendered">
<command:EventToCommand
Command="{Binding ContentRendered}"
CommandParameter="{Binding ElementName=frame}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Frame>

eventtocommand ManipulationCompleted

I'm having a go at writing a small media player for my Windows Phone (more for learning purposes if anything), and am using mvvm-light.
When a video is playing, I have a timer that periodically updates the slider position (and ensures that it's in sync). When I slide the slider around, I pause the timer, so it doesn't skip about.
I use the ManipulationStarted event to pause the timer, and ManipulationComplete to resume it.
I've tried using EventToCommand, but only the ManipulationStarted event fires. When I lift my finger off the phone, ManipulationComplete doesn't fire.
This is my xaml :
<Slider x:Name="PlaybackSlider" HorizontalAlignment="Stretch" Margin="20,0" VerticalAlignment="Bottom" Maximum="{Binding MaxSteps}" Value="{Binding Offset, Mode=TwoWay}" Style="{StaticResource SliderStyle1}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="ManipulationStarted">
<Command:EventToCommand Command="{Binding PlayOffsetBegin}"/>
</i:EventTrigger>
<i:EventTrigger EventName="ManipulationCompleted">
<Command:EventToCommand Command="{Binding PlayOffsetEnd}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<Command:EventToCommand Command="{Binding PlayOffsetUpdate}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Slider>
The bindings are relay commands.
If I implement it like this, it all works fine :
<Slider x:Name="PlaybackSlider"
ManipulationStarted="PlaybackSlider_ManipulationStarted"
ManipulationCompleted="PlaybackSlider_ManipulationCompleted"
HorizontalAlignment="Stretch" Margin="20,0" VerticalAlignment="Bottom"
Maximum="{Binding MaxSteps}" Value="{Binding Offset, Mode=TwoWay}"/>

Categories