Windows phone 8滑块绑定仅在单击后才起作用

时间:2014-03-01 14:25:38

标签: c# windows-phone-8 slider mediaelement

我正在Windows Phone 8上编写音频应用程序。我创建了一个MediaElement和一个搜索栏(滑块):

<MediaElement x:Name="player" CurrentStateChanged="GetTrackDuration" />
<Slider x:Name="playerSeekBar" Value="{Binding ElementName=player, Path=Position, 
 Mode=TwoWay, Converter={StaticResource PositionConverter}}" SmallChange="1" LargeChange="1"/>

这是我的转换器代码:

public class PositionConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double position = 0;
        TimeSpan timespan = TimeSpan.Parse(value.ToString());
        position = timespan.TotalSeconds;

        return position;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
            return TimeSpan.FromSeconds((double)value);
    }
}

这是CurrentStateChanged事件代码:

private void GetTrackDuration(object sender, RoutedEventArgs e)
{
    var player = (MediaElement)sender;
    if (player.CurrentState == System.Windows.Media.MediaElementState.Playing)
        playerSeekBar.Maximum = player.NaturalDuration.TimeSpan.TotalSeconds;
}

这一切似乎都运行正常,但是滑块绑定存在一个问题 - 直到我点击应用程序内的某处才会更新 - 我的意思是我可能会点击一个未与滑块连接的按钮或媒体元素或在空的空间。点击后,滑块正在更新,一切正常。顺便说一句,音乐正常播放 - 即使在滑块没有更新时也是如此。我试着在互联网上看,但是我不知道该问什么,这就是我向你求助的原因。如果有人知道我在哪里可以搜索解决方案,我将非常感激!:)

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

当Slider获得Focus时看起来像一个问题,我试图找到一个重定向Focus的解决方案,但到目前为止 - 我还没有找到它。相反,我对你的代码提出了不同的建议和一些评论:

  1. 播放媒体时获取曲目的持续时间,而不是PlayState更改时:

    private void player_MediaOpened(object sender, RoutedEventArgs e)
    {
        playerSeekBar.Maximum = (sender as MediaElement).NaturalDuration.TimeSpan.TotalSeconds;
    }
    
  2. 您的Slider可能会在MediaElement位置的每一个小变化时更新。我认为不需要它 - 它可以每秒更新一次。所以我的建议是 - 将你的Slider绑定到一个属性,并每秒通知PropertyChanged(使用DispatcherTimer):

    // In this case we need INotifyPropertyChanged - 
    public partial class MainPage : PhoneApplicationPage, INotifyPropertyChanged
    {
    
    // implementing interface
    public event PropertyChangedEventHandler PropertyChanged;
    public void RaiseProperty(string property = null)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(property));
    }
    
    // Property for Binding
    public double SlideValue
    {
        get { return player.Position.TotalSeconds; }
        set { player.Position = TimeSpan.FromSeconds(value); }
    }
    
    DispatcherTimer timer = new DispatcherTimer(); // timer
    
    // Get the duration when Media File is opened
    private void player_MediaOpened(object sender, RoutedEventArgs e)
    {
        playerSeekBar.Maximum = (sender as MediaElement).NaturalDuration.TimeSpan.TotalSeconds;
    }
    
    public MainPage()
    {
        InitializeComponent();
        this.DataContext = this;  // Set the DataContext
        Play.Click += Play_Click;  // My play method
        timer.Interval = TimeSpan.FromSeconds(1);
        timer.Tick += (s, e) => { RaiseProperty("SlideValue"); };
    }
    
    private void Play_Click(object sender, RoutedEventArgs e)
    {
        player.AutoPlay = true;
        player.Source = new Uri("music.mp3", UriKind.RelativeOrAbsolute);
        timer.Start();  // DON'T forget to start the timer.
    }
    
  3. 在这种情况下,您不再需要转换器,您的XAML代码可能如下所示:

    <MediaElement x:Name="player" MediaOpened="player_MediaOpened"/>
    <Slider x:Name="playerSeekBar" Value="{Binding SlideValue, Mode=TwoWay}" SmallChange="1" LargeChange="1"/>
    

    上面的代码可能仍然需要一些改进,但工作得很好。

    编辑 - 没有DataBinding和INotifyPropertyChanged的方法

    只需使用TimerLostMouseCapture,您也可以在没有绑定的情况下更简单地完成任务:

    public partial class MainPage : PhoneApplicationPage
    {
        private double totalSeconds = 1;
    
        DispatcherTimer timer = new DispatcherTimer();
    
        private void player_MediaOpened(object sender, RoutedEventArgs e)
        {
            totalSeconds = (sender as MediaElement).NaturalDuration.TimeSpan.TotalSeconds;
        }
    
        public MainPage()
        {
            InitializeComponent();
            Play.Click += Play_Click;
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += (s, e) => { playerSeekBar.Value += (double)(1 / totalSeconds); };
            playerSeekBar.LostMouseCapture += (s, e) =>
            { player.Position = TimeSpan.FromSeconds(playerSeekBar.Value * totalSeconds); };
        }
    
        private void Play_Click(object sender, RoutedEventArgs e)
        {
            player.AutoPlay = true;
            player.Source = new Uri("music.mp3", UriKind.RelativeOrAbsolute);
            timer.Start();  // DON'T forget to start the timer.
        }
    }
    

    在XAML中:

    <MediaElement x:Name="player" MediaOpened="player_MediaOpened"/>
    <Slider x:Name="playerSeekBar" Value="0" SmallChange="0.01" Maximum="1.0"/>
    

    希望这有帮助。