Xamarin.Forms中UWP项目如何访问PCL内的参数?(树莓派+Windows IoT)
嘿,我来帮你搞定这个跨项目参数访问的问题!结合你用Xamarin Forms、树莓派Windows IoT和I2C开发的场景,核心矛盾其实是跨项目的参数共享加上定时器后台线程的上下文同步,我给你几个落地性强的解决方案:
方案1:用单例模式做共享参数管理(最推荐)
这种方式能让PCL和UWP项目轻松共享参数,而且耦合度低,适合动态修改的参数场景。
首先在PCL项目里新建一个共享参数类(比如放在I2CADDA.Shared命名空间下):
namespace I2CADDA.Shared { public class DeviceParameters { // 单例实例,保证全局唯一 private static readonly DeviceParameters _instance = new DeviceParameters(); public static DeviceParameters Instance => _instance; // 定义你需要共享的参数,比如校准偏移量、采样阈值 private double _calibrationOffset; private int _sampleThreshold; // 线程安全的属性访问(因为定时器是后台线程,可能和UI线程同时操作参数) private readonly object _lockObj = new object(); public double CalibrationOffset { get { lock (_lockObj) return _calibrationOffset; } set { lock (_lockObj) _calibrationOffset = value; } } public int SampleThreshold { get { lock (_lockObj) return _sampleThreshold; } set { lock (_lockObj) _sampleThreshold = value; } } // 私有构造函数,防止外部实例化 private DeviceParameters() {} } }
然后在PCL的MainPage.xaml.cs里设置参数:
// 比如在初始化或用户交互时设置 DeviceParameters.Instance.CalibrationOffset = 0.3; DeviceParameters.Instance.SampleThreshold = 150;
最后在UWP的定时器事件里直接调用:
private void OnTimedEvent(object sender, MicroTimerEventArgs e) { // 直接获取共享参数 var offset = DeviceParameters.Instance.CalibrationOffset; var threshold = DeviceParameters.Instance.SampleThreshold; // 你的模拟输入读取和计算逻辑 var rawAnalogValue = ReadI2CAnalogInput(); var calibratedValue = rawAnalogValue + offset; // 如果需要更新UI,记得切回UI线程(UWP里用Dispatcher) if (calibratedValue > threshold) { Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync( Windows.UI.Core.CoreDispatcherPriority.Normal, () => { // 这里写UI更新逻辑,比如修改TextBlock内容 StatusTextBlock.Text = "超过阈值!"; }); } }
方案2:依赖注入(适合复杂项目)
如果你的项目已经在用依赖注入,或者需要更灵活的参数管理,可以用Xamarin Forms自带的DependencyService:
- 在PCL里定义参数接口和实现类:
public interface IDeviceParameters { double CalibrationOffset { get; set; } int SampleThreshold { get; set; } } public class DeviceParameters : IDeviceParameters { // 和方案1一样的属性实现,带线程锁 private double _calibrationOffset; private int _sampleThreshold; private readonly object _lockObj = new object(); public double CalibrationOffset { get { lock(_lockObj) return _calibrationOffset; } set { lock(_lockObj) _calibrationOffset = value; } } public int SampleThreshold { get { lock(_lockObj) return _sampleThreshold; } set { lock(_lockObj) _sampleThreshold = value; } } }
- 在PCL的
App.xaml.cs里注册单例:
public App() { InitializeComponent(); // 注册参数服务为单例 DependencyService.RegisterSingleton<IDeviceParameters>(new DeviceParameters()); MainPage = new MainPage(); }
- 在PCL和UWP里注入使用:
// PCL的MainPage里设置参数 var paramService = DependencyService.Get<IDeviceParameters>(); paramService.CalibrationOffset = 0.3; // UWP的定时器事件里获取参数 var paramService = DependencyService.Get<IDeviceParameters>(); var offset = paramService.CalibrationOffset;
方案3:直接传递初始化参数(适合静态参数)
如果你的参数是启动时设置好、后续不会修改的,也可以在UWP项目启动时直接从PCL传递:
在UWP的App.xaml.cs里:
protected override void OnLaunched(LaunchActivatedEventArgs e) { // 实例化PCL的MainPage var mainPage = new I2CADDA.MainPage(); // 假设PCL里把参数设为public属性 var calibrationOffset = mainPage.CalibrationOffset; // 把参数存到UWP类的字段里 _calibrationOffset = calibrationOffset; // 初始化并启动微定时器 _microTimer = new MicroTimer { Interval = 100 }; _microTimer.MicroTimerElapsed += OnTimedEvent; _microTimer.Start(); } private double _calibrationOffset; private void OnTimedEvent(object sender, MicroTimerEventArgs e) { // 直接用存储的参数计算 var calibratedValue = ReadI2CAnalogInput() + _calibrationOffset; }
关键注意点
- 线程安全:如果参数会被UI线程(PCL)和后台定时器线程同时读写,一定要加锁,避免数据错乱。
- UI线程同步:定时器事件是在后台线程执行的,不能直接操作UI,必须用UWP的
Dispatcher切回UI线程再更新。 - 避免直接访问PCL的MainPage实例:MainPage是UI元素,后台线程直接访问可能引发上下文异常,而且耦合性太高,不利于后续维护。
内容的提问来源于stack exchange,提问作者Tschiwen Gu
相关产品推荐
相关产品推荐

