Xamarin.Forms页面导航:扫码完成后返回原页并传递条形码值方案咨询
问题分析
你现有代码的核心逻辑错误是:调用await Navigation.PushAsync(scanner);后立刻执行了await Navigation.PopAsync();,会导致刚跳转到扫描页就立即回退,完全没有等待用户扫描操作完成,自然无法拿到扫描结果。
另外你全局缓存了ScanningPage实例,多次进入扫描页会出现状态残留的问题,不推荐这么写。
实现方案推荐
方案1:回调委托实现(最简洁,无额外依赖)
直接给扫描页增加扫描完成的回调委托,扫描成功后执行回调并自动回退,不需要额外引入组件。
修改ScanningPage代码:
public partial class ScanningPage : ContentPage { // 新增扫描完成的回调属性 public Action<string> OnScanCompleted { get; set; } public ScanningPage() { InitializeComponent(); } private void _scanView_OnScanResult(ZXing.Result result) { Device.BeginInvokeOnMainThread(async () => { var scanResult = result.Text; // 触发回调传值 OnScanCompleted?.Invoke(scanResult); // 扫描完成后自动回退到上一页 await Navigation.PopAsync(); }); } }
修改MainPage代码:
public partial class MainPage : ContentPage { private string barcodeValue; public MainPage() { InitializeComponent(); barcodeValue = ""; } async private void UrlButton_Clicked(object sender, EventArgs e) { // 每次进入扫描页都创建新实例,避免状态残留 var scannerPage = new ScanningPage(); // 注册扫描完成的回调逻辑 scannerPage.OnScanCompleted = (barcode) => { scannResultText.Text = barcode; barcodeValue = barcode; }; // 跳转到扫描页,不需要在这里写Pop逻辑 await Navigation.PushAsync(scannerPage); } }
方案2:事件订阅实现
你也可以通过给ScanningPage定义自定义事件的方式实现传值,逻辑和回调类似:
- 在ScanningPage中定义
public event EventHandler<string> ScanCompleted;事件 - 扫描完成时触发事件:
ScanCompleted?.Invoke(this, result.Text); - MainPage创建ScanningPage实例后,订阅
ScanCompleted事件,在事件处理方法中给控件赋值即可
方案3:消息中心实现(适合解耦层级较深的场景)
如果你的项目中使用了MVVM架构,页面层级较深,可以用消息中心实现跨页面传值:
- Xamarin.Forms 可使用自带的
MessagingCenter - MAUI 推荐使用CommunityToolkit.Mvvm中的
WeakReferenceMessenger
扫描完成后在ScanningPage发送携带条码值的消息,MainPage订阅对应消息接收值即可。
注意事项
- 不要全局缓存页面实例,每次跳转创建新实例可以避免之前的扫描结果残留、扫描控件状态异常等问题
- 扫描完成的回退逻辑放在ScanningPage内部触发更符合单页职责的设计原则
内容的提问来源于stack exchange,提问作者Filip from Poland
相关产品推荐
相关产品推荐

