【问题标题】:Event handling in Windows Store Apps using MVVM使用 MVVM 在 Windows 应用商店应用程序中处理事件
【发布时间】:2014-02-03 01:49:57
【问题描述】:

我正在使用 MVVM 模式(没有框架,只有原始 MVVM)开发一个 Windows 应用商店应用程序。

我有一个用户控件DropboxFileplanUserControl.xaml,它有一个关联的视图模型DropboxFileplanViewModel.csDropboxFileplanUserControl 嵌入在 MainPage.xaml 中,MainPage.xaml 具有关联的视图模型 MainPageViewModel.cs

我的问题是如何在DropboxFileplanViewModel.cs 中定义和引发事件并在MainPageViewModel.cs 中处理它?假设要引发的事件称为ImageLoaded

编辑:我添加了以下具体代码sn-ps...

DropboxFileplanUserControl.xaml

<UserControl
x:Class="PhotoBox.Controls.DropboxFileplanUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PhotoBox.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="using:PhotoBox.ViewModels"
xmlns:triggers="using:WinRT.Triggers"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="200">

<UserControl.DataContext>
    <viewModels:DropboxFileplanViewModel />
</UserControl.DataContext>

<Grid>
    <ListBox>
    <!-- 
        ...
        ...
        Here I define a ListBox and use interaction triggers to bind the SelectionChanged event to FileplanSelectionChangedCommand on the ViewModel -->
         <triggers:Interactions.Triggers>
            <triggers:EventTrigger EventName="SelectionChanged">
                <triggers:InvokeCommandAction Command="{Binding FileplanSelectionChangedCommand}" PassEventArgsToCommand="True" />
            </triggers:EventTrigger>
        </triggers:Interactions.Triggers>
    </ListBox>
</Grid>

DropboxFileplanViewModel.xaml 注意:我已经从这个 sn-p 中删除了很多代码

public class DropboxFileplanViewModel : ViewModel
{
    public DelegateCommand FileplanSelectionChangedCommand { get; set; }

    public DropboxFileplanViewModel()
    {
        FileplanSelectionChangedCommand = new DelegateCommand(FileplanSelectionChanged);
    }

    private void FileplanSelectionChanged(object parameter)
    {
        var args = (SelectionChangedEventArgs) parameter;

        // Some other stuff is done here but ultimately,
        // GetImageFile is called

    }

    private async void GetImageFile(MetaData file)
    {
        // Stuff is done here to get the image

        // ******************************                        
        // Here I want to raise the event
        // ******************************    
    }
}

DropboxFileplanUserControl嵌入MainPage.xaml如下...

MainPage.xaml

<controls:DropboxFileplanUserControl
            Grid.Row="0"
            DataContext="{Binding FileplanControl}"
            Visibility="{Binding IsOpen, Converter={StaticResource BooleanToVisibilityConverter}}"
            IsEnabled="{Binding IsOpen}"
            <!-- *** Here I need to access the ImageLoaded event and bind it to a command in MainPageViewModel.cs *** -->
            />

所以,总而言之,我需要在DropboxFileplanViewModel.cs 中声明并引发一个事件,并在MainPage.xaml 中访问此事件,以便我可以在MainPageViewModel.cs 中处理它。我知道如何将MainPage.xaml 中的事件绑定到MainPageViewModel 中的命令,我只需要知道如何做第一个,即在DropboxFileplanViewModel.cs 中声明和引发事件并在MainPage.xaml 中访问它。

【问题讨论】:

  • 您是否使用基类来存储您的视图模型,例如 ViewModelLocator (mvvm light)?您可以为您的 xaml 和视图模型添加一些代码吗?
  • 我的视图模型的继承层次是ViewModel : BindableBase : INotifyPropertyChanged。关于类名,我尽量让我的原始问题保持一般性,但我将使用实际代码 sn-ps 编辑帖子。
  • 感谢您的代码。一个简单的方法是在 mvvmlight 中使用 Messenger 类,但我认为我会在给出答案之前先检查一下,因为你没有使用框架。

标签: c# xaml mvvm windows-runtime windows-store-apps


【解决方案1】:

在 XAML 中:

<Image Loaded="ImageLoaded" ... />

在 xaml.cs 中:

public MainPageViewModel ViewModel
{
    get
    {
        return this.DataContext as MainPageViewModel;
    }
}

public void ImageLoaded( object sender, RoutedEventArgs args )
{
    // call down to your view model
    if( ViewModel != null )
    {
        ViewModel.ImageLoadedHandler( );
    }
}

针对您的评论,自定义UserControl 的想法是相同的。我有(我认为是)和有趣的解决方案,我不经常看到其他人实施。这是每个 ViewModel 都有一个关联的 View(我称之为所有者)和一个逻辑父级的想法。与允许遍历 UI 元素的可视化树 XAML/WinRT 构造类似,我们可以在 ViewModel 中创建的父/所有者关系允许在我们的后端代码中进行相同的遍历样式。考虑以下几点:

假设我们有一个名为 MyUserControl 的自定义 UserControl,它驻留在命名空间 MyProject 中。

在 MainPageView.xaml 中:

<Page xmlns:local="MyProject"> // or whatever your fancy-pants namespace scheme is
    <Grid>
        <local:MyUserControl DataContext="{Binding InnerVM}" />
    </Grid>
</Page>

在你的 MainPageView.xaml.cs

public MainPageViewModel ViewModel
{
    get
    {
        return this.DataContext as MainPageViewModel;
    }
}

public MainPageView()
{
    InitializeComponent( );

    DataContext = new MainPageViewModel( null, this );
}

我们快到了。现在让我们看看 MainPageViewModel.cs

public MainPageViewModel : ViewModelBase // I'll explain ViewModelBase momentarily
{
    public MyUserControlViewModel InnerVM { get; set; } // should be a notifying property

    public MainPageViewModel( ViewModelBase parent, FrameworkElement owner )
        : base( parent, owner )
    {
    }
}

出于所有意图和目的,MyUserControlViewModel.cs 是相同的。

这里是 ViewModelBase.cs(有一些删节):

public ViewModelBase
{
    public ViewModelBase Parent { get; set; } // should be a notifying property
    public FrameworkElement Owner { get; set; } // should be a notifying property

    public ViewModelBase( ViewModelBase parent, FrameworkElement owner )
    {
        Parent = parent;
        Owner = owner;
    }
}

简单!正确的?现在这对我们有什么实际作用?让我们来看看。考虑以下几点:

在 MyUserControl.xaml 中:

<Image Loaded="ImageLoaded" ... />

在 MyUserControl.xaml.cs 中:

public MyUserControlVieWModel ViewModel
{
    get
    {
        return this.DataContext as MyUserControlVieWModel;
    }
}

public void ImageLoaded( object sender, RoutedEventArgs args )
{
    // call down to your view model
    if( ViewModel != null )
    {
        ViewModel.ImageLoadedHandler( );
    }
}

MyUserControlViewModel.cs

现在您有两个选择(我刚刚意识到我可能为您解释了这个问题,我很抱歉。请认真考虑您的问题的选项 1):

1- 使用事件!

public event EventHandler ImageLoaded = delegate { };

public void OnImageLoaded( )
{
    ImageLoaded( );
}

然后在 MainPageViewModel.cs 中

public void OnImageLoaded( )
{
    // handle the image loading
}

现在也许把它放在你的构造函数中:

...
InnerVM.ImageLoaded += OnImageLoaded;
...

现在当事件从 MyUserControl 中触发时,MainPageViewModel 将能够响应。

第二个选项需要更多解释,我现在必须运行。但希望这能让你继续前进。对不起,短暂的结局。如果需要,请回答问题。祝你好运!

【讨论】:

  • 感谢William,它给了我处理MainPageViewModel.cs 中事件的代码。也许我的问题并不清楚,但我需要从用户控件的视图模型MyUserControlViewModel.cs 中引发事件。用户控件本身MyUserControl.xaml 嵌入在MainPage.xaml 中。您能否提供一个代码 sn-p 来说明如何实现?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多