传递一个对象给UserControl来控制它

本文关键字:控制 UserControl 一个对象 | 更新日期: 2023-09-27 18:07:50

我试图将在MainWindow中创建的对象传递给我的UserControl,它将读取和修改它,但它不知道为什么。下面是我使用的代码:

MainWindow class:

public partial class MainWindow : Window
{
    public SupremeLibrary.Player player = new SupremeLibrary.Player();
    public MainWindow()
    {
        InitializeComponent();
        MusicSeekBar = new Components.SeekBar(player);
    }
}

SeekBar用户控制:

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,如果我使用

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

作为静态并在UserControl中称为MainWindow.player,但它很丑,我不想使用它。

我试图通过playerMainWindow作为参考,但它似乎也不起作用。

传递一个对象给UserControl来控制它

使用MediaElement的例子

用户控制搜索栏

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>

我已经在控件中定义了一个滑动条,它绑定到控件的TotalMilliseconds和CurrentPosition的最大值和value属性,这些属性将绑定到控件本身,因为我已经将控件的DataContext设置为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;
        }
    }
}

我做了什么

  • 在UI
  • 上定义的媒体元素播放器属性
  • 附加MediaOpened和MediaEnded,用于启动和停止计时器并更新持续时间。
  • 在控件UI
  • 中定义滑块控件的当前位置和总持续时间的属性
  • 和当前位置的变化,我将更新回球员的位置。

主窗口使用情况

<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>

我将media元素绑定到我的SeekBar控件的Player属性

通过这样做,我没有在代码中做任何硬编码,也通过接口,你可以实现你的搜索栏和播放器之间的更大的解耦

这只是一个简单的例子,你可以在上面的例子中使用你的自定义播放器和进度控制来实现你的结果。