You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于MVVM模式的WinUI3框架页面间数据共享方案咨询

WinUI3页面间共享选中影片数据的正确实现方式

当前代码存在的核心问题:MediaCenterPage和PlayerPage各自在XAML中实例化了MediaModel,导致两个页面的DataContext是独立的对象实例,无法共享选中数据;同时用静态字段SelectedMovie传递数据不符合MVVM规范,还可能引发内存泄漏风险。以下是三种可行的解决方式:


方案一:导航时直接传递选中对象

利用WinUI的Frame导航传参能力,直接将选中的MediaObject实例传给PlayerPage,是最直接的实现方式。

修改MediaCenterPage的导航逻辑

// MediaCenterPage.xaml.cs
private void MediaCenterItemView_PointerPressed(object sender, PointerRoutedEventArgs e)
{
    if (MediaCenterItemView.SelectedItem is MediaObject selectedMovie)
    {
        Frame.Navigate(typeof(PlayerPage), selectedMovie);
    }
}

PlayerPage接收并使用参数

// PlayerPage.xaml.cs
public sealed partial class PlayerPage : Page
{
    private MediaObject _selectedMovie;

    public PlayerPage()
    {
        this.InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        _selectedMovie = e.Parameter as MediaObject;
        if (_selectedMovie != null)
        {
            MediaPlayer.Source = _selectedMovie.Movie;
        }
    }

    private void BackButton_Click(object sender, RoutedEventArgs e)
    {
        MainPage.MainFrame.Navigate(typeof(MediaCenterPage));
    }
}

方案二:使用单一共享的ViewModel实例

创建全局唯一的MediaModel实例,让两个页面绑定同一个ViewModel,选中数据的变更会自动同步。

1. 创建全局ViewModel实例

在App.xaml.cs中定义全局共享实例:

// App.xaml.cs
using WinUI3Demo.ViewModels;

namespace WinUI3Demo
{
    public partial class App : Application
    {
        public static MediaModel SharedMediaModel { get; } = new MediaModel();
        
        // ...其他原有代码
    }
}

2. 修改页面的DataContext绑定

MediaCenterPage.xaml

替换原有的<Page.DataContext>:

<Page
    x:Class="WinUI3Demo.Pages.MediaCenter.MediaCenterPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:WinUI3Demo"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">
    <Page.DataContext>
        <Binding Source="{x:Bind local:App.SharedMediaModel}" />
    </Page.DataContext>
    
    <!-- 原有页面内容 -->
</Page>

PlayerPage.xaml同理修改:

<Page
    x:Class="WinUI3Demo.Pages.MediaCenter.PlayerPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:WinUI3Demo"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">
    <Page.DataContext>
        <Binding Source="{x:Bind local:App.SharedMediaModel}" />
    </Page.DataContext>
    
    <!-- 原有页面内容 -->
</Page>

3. 更新选中逻辑到ViewModel

// MediaCenterPage.xaml.cs
private void ItemsView_SelectionChanged(ItemsView sender, ItemsViewSelectionChangedEventArgs args)
{
    if (MediaCenterItemView.SelectedItem is MediaObject selectedMovie)
    {
        HeaderTextBlock.Text = selectedMovie.Title;
        ContentTextBlock.Text = selectedMovie.Description;
        App.SharedMediaModel.SelectedMovie = selectedMovie;
    }
}

4. PlayerPage绑定选中项的媒体源

修改PlayerPage的MediaPlayerElement绑定:

<MediaPlayerElement
    x:Name="MediaPlayer"
    AreTransportControlsEnabled="True"
    AutoPlay="True"
    Source="{x:Bind SelectedMovie.Movie, Mode=OneWay}" />

方案三:使用消息传递(适合复杂场景)

如果页面层级复杂或不想依赖全局实例/导航参数,可以用Microsoft.Toolkit.Mvvm的消息传递功能实现解耦。

1. 安装NuGet包

安装Microsoft.Toolkit.Mvvm包。

2. 定义消息类

// ViewModels/Messages/MediaSelectedMessage.cs
namespace WinUI3Demo.ViewModels.Messages
{
    public class MediaSelectedMessage
    {
        public MediaObject SelectedMovie { get; }

        public MediaSelectedMessage(MediaObject selectedMovie)
        {
            SelectedMovie = selectedMovie;
        }
    }
}

3. MediaCenterPage发送消息

// MediaCenterPage.xaml.cs
using Microsoft.Toolkit.Mvvm.Messaging;
using WinUI3Demo.ViewModels.Messages;

private void MediaCenterItemView_PointerPressed(object sender, PointerRoutedEventArgs e)
{
    if (MediaCenterItemView.SelectedItem is MediaObject selectedMovie)
    {
        WeakReferenceMessenger.Default.Send(new MediaSelectedMessage(selectedMovie));
        Frame.Navigate(typeof(PlayerPage));
    }
}

4. PlayerPage接收消息

// PlayerPage.xaml.cs
using Microsoft.Toolkit.Mvvm.Messaging;
using WinUI3Demo.ViewModels.Messages;

public sealed partial class PlayerPage : Page
{
    private MediaObject _selectedMovie;
    private IDisposable _messageSubscription;

    public PlayerPage()
    {
        this.InitializeComponent();
        _messageSubscription = WeakReferenceMessenger.Default.Register<MediaSelectedMessage>(this, (recipient, message) =>
        {
            _selectedMovie = message.SelectedMovie;
            MediaPlayer.Source = _selectedMovie.Movie;
        });
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        base.OnNavigatedFrom(e);
        _messageSubscription?.Dispose();
    }

    private void BackButton_Click(object sender, RoutedEventArgs e)
    {
        MainPage.MainFrame.Navigate(typeof(MediaCenterPage));
    }
}

内容的提问来源于stack exchange,提问作者miniHessel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 18:42:02