简体   繁体   English

Windows应用商店中使用MVVM的事件处理

[英]Event handling in Windows Store Apps using MVVM

I am developing a Windows Store App using the MVVM pattern (no framework, just raw MVVM). 我正在使用MVVM模式(没有框架,只是原始MVVM)开发Windows应用商店。

I have a user control DropboxFileplanUserControl.xaml which has an associated view model DropboxFileplanViewModel.cs . 我有一个用户控件DropboxFileplanUserControl.xaml ,它具有关联的视图模型DropboxFileplanViewModel.cs DropboxFileplanUserControl is embedded in MainPage.xaml and MainPage.xaml has an associated view model, MainPageViewModel.cs . DropboxFileplanUserControl嵌入在MainPage.xaml并且MainPage.xaml具有关联的视图模型MainPageViewModel.cs

My question is how can I define and raise an event in DropboxFileplanViewModel.cs and handle it in MainPageViewModel.cs ? 我的问题是如何在DropboxFileplanViewModel.cs定义和引发事件并在MainPageViewModel.cs处理它? Assume the event to be raised is called ImageLoaded . 假设要引发的事件称为ImageLoaded

EDIT: I have added the following specific code snippets... 编辑:我添加了以下特定的代码段...

DropboxFileplanUserControl.xaml 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 Note: I've stripped out a lot of code from this snippet DropboxFileplanViewModel.xaml 注意:我从这段代码中剥离了很多代码

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 is embedded in MainPage.xaml as follows... DropboxFileplanUserControl嵌入在MainPage.xaml ,如下所示...

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 *** -->
            />

So, to summarise, I need to declare and raise an event in DropboxFileplanViewModel.cs and access this event in MainPage.xaml so I can then handle it in MainPageViewModel.cs . 因此,总而言之,我需要在DropboxFileplanViewModel.cs声明并引发一个事件,并在MainPage.xaml访问此事件,以便随后可以在MainPageViewModel.cs对其进行处理。 I know how to bind the event in MainPage.xaml to a command in MainPageViewModel , I just need to know how to do the first bit, ie declaring and raising an event in DropboxFileplanViewModel.cs and accessing it in MainPage.xaml . 我知道如何在绑定事件MainPage.xaml要在命令MainPageViewModel ,我只需要知道如何做的第一位,即宣布,提高在事件DropboxFileplanViewModel.cs和访问它MainPage.xaml

In XAML: 在XAML中:

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

In xaml.cs: 在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( );
    }
}

In response to your comment, the idea is the same for the custom UserControl . 为了回应您的评论,自定义UserControl的想法是相同的。 I have (what I think is) and interesting solution I don't often see others implement. 我有(我认为是什么)和有趣的解决方案,我很少看到其他人实现。 It's the idea that each ViewModel has an associated View (I call it owner) and a logical parent. 这个想法是每个ViewModel都有一个关联的View(我称其为owner)和一个逻辑父级。 Similar to the visual tree XAML/WinRT constructs that allows for traversal of UI elements, the parent/owner relationship we can create in our ViewModels allow this same style of traversal in our back-end code. 与允许遍历UI元素的可视树XAML / WinRT构造类似,我们可以在ViewModels中创建的父/所有者关系允许在后端代码中使用相同的遍历样式。 Consider the following: 考虑以下:

Assume we have a custom UserControl called MyUserControl that resides in the namespace MyProject . 假设我们有一个名为MyUserControl的自定义UserControl ,它位于命名空间MyProject

In MainPageView.xaml: 在MainPageView.xaml中:

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

In you MainPageView.xaml.cs 在您的MainPageView.xaml.cs中

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

public MainPageView()
{
    InitializeComponent( );

    DataContext = new MainPageViewModel( null, this );
}

We're getting there. 我们到了那里。 Now let's look at MainPageViewModel.cs 现在让我们看一下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 )
    {
    }
}

For all intents and purposes, MyUserControlViewModel.cs is the same. 出于所有目的和目的,MyUserControlViewModel.cs是相同的。

Here is ViewModelBase.cs (with some abridgments): 这是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;
    }
}

Simple! 简单! Right? 对? Now what does that actually do for us? 现在,这实际上对我们有什么作用? Let's see. 让我们来看看。 Consider the following: 考虑以下:

In MyUserControl.xaml: 在MyUserControl.xaml中:

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

In MyUserControl.xaml.cs: 在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 MyUserControlViewModel.cs

Now you have two options here (and I just realized I may be over-explaining the issue for you, and I apologize. Please heavily consider option 1 for your question): 现在您在这里有两个选择(我刚刚意识到我可能为您过度说明了这个问题,对不起。请为您的问题认真考虑选择1):

1- Use Events! 1-使用事件!

public event EventHandler ImageLoaded = delegate { };

public void OnImageLoaded( )
{
    ImageLoaded( );
}

Then in MainPageViewModel.cs 然后在MainPageViewModel.cs中

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

And now maybe put this in your constructor: 现在,也许将其放入您的构造函数中:

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

Now when the event is fired from within MyUserControl, MainPageViewModel will be able to respond. 现在,当从MyUserControl内部触发事件时,MainPageViewModel将能够响应。

The second option requires more explination, and I have to run for now. 第二个选项需要更多的解释,我现在必须运行。 But hopefully this gets you going. 但是希望这可以帮助您前进。 Sorry for the short ending. 对不起,短片。 Please respond with questions if you need to. 如果需要,请回答问题。 Good luck! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM