我对只读Bindable Property的Getter实现是否正确?
你的Getter实现并不正确,这里是问题所在和修正方案
首先得明确:你自己在ViewModel里定义的VideoState属性,和Rox NuGet包中VideoView控件提供的只读VideoState属性是完全两个独立的东西。你的videoState字段从来没有被赋值过,所以它一直是VideoStateType枚举的默认值(大概率是Empty),这也是你控制台没看到有效输出的核心原因之一。
另外,你的Console.WriteLine写法也有问题:
Console.WriteLine("The VideoState is ", videoState);
这种写法不会把videoState的值插入到字符串里,你需要用占位符或者字符串插值:
// 占位符写法 Console.WriteLine("The VideoState is {0}", videoState); // 字符串插值(C# 6+) Console.WriteLine($"The VideoState is {videoState}");
正确的实现方式:监听VideoView的属性变化
要获取VideoView的真实VideoState,你需要监听控件本身的PropertyChanged事件,在事件触发时读取控件的VideoState属性,而不是自己定义一个同名属性。
步骤1:修正ViewModel的逻辑
把你自己定义的VideoState属性删掉,转而在属性变化方法里直接获取控件的VideoState值:
using System.ComponentModel; using Xamarin.Forms; using Rox; namespace PreAppStructure { public class RoxViewModel : INotifyPropertyChanged { private bool _isBusy; public bool IsBusy { get => _isBusy; set { _isBusy = value; OnPropertyChanged(nameof(IsBusy)); } } // 用于接收VideoView的属性变化事件 public void OnVideoViewPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(VideoView.VideoState)) { if (sender is VideoView videoView) { // 这里直接读取控件的VideoState属性 var currentState = videoView.VideoState; Console.WriteLine($"The VideoState is {currentState}"); // 根据状态设置IsBusy IsBusy = currentState == VideoStateType.Buffering; } } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
步骤2:在页面后台绑定事件
因为VideoView是XAML中的控件,你需要在页面的代码后台(Page3.xaml.cs)中把控件的PropertyChanged事件绑定到ViewModel的方法上:
using Xamarin.Forms; namespace PreAppStructure { public partial class Page3 : ContentPage { public Page3() { InitializeComponent(); var viewModel = new RoxViewModel(); BindingContext = viewModel; // 绑定VideoView的PropertyChanged事件到ViewModel的方法 VideoView.PropertyChanged += viewModel.OnVideoViewPropertyChanged; } } }
步骤3:调整XAML的命令绑定(可选)
如果你想用PropertyChangedCommand而不是直接绑定事件,需要确保ViewModel中有对应的ICommand属性,并传递控件实例:
// 在ViewModel中添加 public ICommand PropertyChangedCommand { get; } // 在构造函数中初始化 public RoxViewModel() { PropertyChangedCommand = new Command<object>((param) => { if (param is PropertyChangedEventArgs args && args.PropertyName == nameof(VideoView.VideoState)) { if (VideoView != null) { var currentState = VideoView.VideoState; IsBusy = currentState == VideoStateType.Buffering; } } }); }
对应的XAML调整:
<roxv:VideoView x:Name="VideoView" AutoPlay="True" LoopPlay="True" ShowController="True" Source="http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4" PropertyChangedCommand="{Binding PropertyChangedCommand}" PropertyChangedCommandParameter="{x:Reference VideoView}"/>
不过这种方式需要处理控件实例的传递,不如直接绑定事件直观。
为什么之前的控制台没有输出?
- 你的
videoState字段从未被赋值,一直是枚举默认值,即使格式正确,输出的也是默认值。 Console.WriteLine的格式错误,没有把变量插入到字符串中,所以只会输出固定文本,看不到变量值。
按照上面的修正方案,你应该能正确获取VideoView的状态,并且在Buffering时显示加载指示器了。
内容的提问来源于stack exchange,提问作者Tom F
相关产品推荐
相关产品推荐

