Kuba Wasilczyk
Kuba Wasilczyk

Reputation: 1167

Pass an object to UserControl which will control it

I'm trying to pass an object created in MainWindow to my UserControl that will read and modify it but it doesn't don't know why. Here is the code I'm using:

MainWindow class:

public partial class MainWindow : Window
{
    public SupremeLibrary.Player player = new SupremeLibrary.Player();

    public MainWindow()
    {
        InitializeComponent();
        MusicSeekBar = new Components.SeekBar(player);

    }
}

And SeekBar user control:

public partial class SeekBar : UserControl
{
    DispatcherTimer Updater = new DispatcherTimer();
    SupremeLibrary.Player player;

    /// <summary>
    /// Initialize new Seekbar
    /// </summary>
    public SeekBar()
    {
        InitializeComponent();
        InitializeUpdater();
    }

    public SeekBar(SupremeLibrary.Player _player)
    {
        player = _player;
        InitializeComponent();
        InitializeUpdater();
    }

    private void InitializeUpdater()
    {
        Updater.Interval = TimeSpan.FromMilliseconds(100);
        Updater.Tick += UpdateSeekBar;
        Updater.Start();
    }

    private void UpdateSeekBar(object sender, EventArgs e)
    {
        if (player != null)
        {
            if (player.PlaybackState == SupremeLibrary.PlaybackStates.Playing)
            {
                if (player.Position.TotalMilliseconds != CustomProgressBar.Value) CustomProgressBar.Value = player.Position.TotalMilliseconds;
                if (player.MaxPosition.TotalMilliseconds != CustomProgressBar.Maximum) CustomProgressBar.Maximum = player.MaxPosition.TotalMilliseconds;
            }
        }
    }

    private void PB_SeekBar_ChangeValue(object obj, MouseEventArgs e)
    {
        if (player != null)
        {
            if (player.PlaybackState == SupremeLibrary.PlaybackStates.Playing)
            {
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    player.Position = TimeSpan.FromMilliseconds(e.GetPosition(obj as ProgressBar).X / ((obj as ProgressBar).ActualWidth / 100) * ((obj as ProgressBar).Maximum / 100));
                }
            }
        }
    }

In add, it works if I use

public SupremeLibrary.Player player = new SupremeLibrary.Player();

as static and call it in UserControl as MainWindow.player but it's ugly and I don't want to use it.

I have tried to pass player from MainWindow as reference but it doesn't seem to work either.

Upvotes: 0

Views: 1075

Answers (1)

pushpraj
pushpraj

Reputation: 13669

Example using MediaElement

user control SeekBar

XAML

<UserControl x:Class="CSharpWPF.SeekBar"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             DataContext="{Binding RelativeSource={RelativeSource Self}}" >
        <Slider Maximum="{Binding TotalMilliseconds}"
                Value="{Binding CurrentPosition}"/>
</UserControl>

i have defined a Slider in the control with binding to the maximum and value property to the TotalMilliseconds and CurrentPosition of the control, the properties will be bound to the control itself as I have set the DataContext of the control to self

.cs

public partial class SeekBar : UserControl
{
    DispatcherTimer Updater = new DispatcherTimer();

    /// <summary>
    /// Initialize new Seekbar
    /// </summary>
    public SeekBar()
    {
        InitializeComponent();
        InitializeUpdater();
    }

    private void InitializeUpdater()
    {
        Updater.Interval = TimeSpan.FromMilliseconds(100);
        Updater.Tick += UpdateSeekBar;
    }

    public MediaElement Player
    {
        get { return (MediaElement)GetValue(PlayerProperty); }
        set { SetValue(PlayerProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Player.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty PlayerProperty =
        DependencyProperty.Register("Player", typeof(MediaElement), typeof(SeekBar), new PropertyMetadata(null, OnPlayerChanged));

    private static void OnPlayerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        SeekBar seekB = d as SeekBar;

        if (e.OldValue != null)
        {
            SeekBar oldSeekB = (e.OldValue as SeekBar);
            oldSeekB.Player.MediaOpened -= seekB.Player_MediaOpened;
            oldSeekB.Player.MediaEnded -= seekB.Player_MediaEnded;
        }

        if (seekB.Player != null)
        {
            seekB.Player.MediaOpened += seekB.Player_MediaOpened;
            seekB.Player.MediaEnded += seekB.Player_MediaEnded;
        }
    }

    void Player_MediaEnded(object sender, RoutedEventArgs e)
    {
        Updater.Stop();
    }

    private void Player_MediaOpened(object sender, RoutedEventArgs e)
    {
        if (Player.NaturalDuration.HasTimeSpan)
        {
            TotalMilliseconds = Player.NaturalDuration.TimeSpan.TotalMilliseconds;
            Updater.Start();
        }
        else
        {
            CurrentPosition = 0.0;
            TotalMilliseconds = 1.0;
        }
    }

    public double CurrentPosition
    {
        get { return (double)GetValue(CurrentPositionProperty); }
        set { SetValue(CurrentPositionProperty, value); }
    }

    // Using a DependencyProperty as the backing store for CurrentPosition.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CurrentPositionProperty =
        DependencyProperty.Register("CurrentPosition", typeof(double), typeof(SeekBar), new PropertyMetadata(1.0, OnCurrentPositionChange));

    private static void OnCurrentPositionChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        SeekBar seekB = d as SeekBar;
        if (seekB.Player != null)
        {
            seekB.Player.Position = TimeSpan.FromMilliseconds(seekB.CurrentPosition);
        }
    }

    public double TotalMilliseconds
    {
        get { return (double)GetValue(TotalMillisecondsProperty); }
        set { SetValue(TotalMillisecondsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for TotalMilliseconds.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TotalMillisecondsProperty =
        DependencyProperty.Register("TotalMilliseconds", typeof(double), typeof(SeekBar), new PropertyMetadata(0.0));


    private void UpdateSeekBar(object sender, EventArgs e)
    {
        if (Player != null && TotalMilliseconds > 1)
        {
            CurrentPosition = Player.Position.TotalMilliseconds;
        }
    }
}

what I have done

  • defined property Player of Media Element to be bound at UI
  • attached MediaOpened and MediaEnded for the purpose of starting and stopping the timer adn updating the duration.
  • defined properties for current position and total duration for my slider control in the control UI
  • and on change of CurrentPosition, I'll update back the player's position.

usage in main window

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="auto" />
    </Grid.RowDefinitions>
    <MediaElement x:Name="media"
                  Source="Wildlife.wmv" />
    <l:SeekBar Grid.Row="1"
               Player="{Binding ElementName=media}" />
</Grid>

I'll just bind the media element to the Player property of my SeekBar control

by doing in this way I've not done any hard coding in code behind, also by means of interface you can achieve a greater decoupling between your seekbar and the player

this is just a simple example for your case, you may use your custom player and progress control in the above example to achieve your results.

Upvotes: 1

Related Questions