2014-01-14 31 views
2

我正在使用MVVM模式(无框架,只是原始的MVVM)开发Windows应用商店应用程序。使用MVVM的Windows商店应用程序中的事件处理

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

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

编辑:我已经添加了以下具体的代码片段...

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注:我已经剥离了很多来自此片段的代码

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中访问它。

+0

您是否使用基类来存储ViewModelLocator(mvvm light)等视图模型?你可以把一些代码放到你的xaml和viewmodels中吗? – SWilko

+0

我的viewmodels的继承层次结构是'ViewModel:BindableBase:INotifyPropertyChanged'。我尽量保持原始问题的类名尽可能通用,但我会用实际的代码片段编辑帖子。 –

+0

感谢您的代码。一个简单的方法就是使用mvvmlight中的Messenger类,但是我认为在你不使用框架之前先检查答案。 – SWilko

回答

3

在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中创建的父/所有者关系允许在后端代码中使用相同的遍历样式。考虑以下内容:

假设我们有一个自定义UserControl,称为MyUserControl,它位于命名空间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就能响应。

第二个选项需要更多的探索,我必须现在运行。但希望这会让你走。对不起,短的结局。如果您需要,请回答问题。祝你好运!

+0

感谢William,它给了我在'MainPageViewModel.cs'中处理事件的代码。也许我不清楚我的问题,但我需要从用户控件的视图模型MyUserControlViewModel.cs中引发事件。用户控制自己'MyUserControl.xaml'嵌入在'MainPage.xaml'中。你能否提供一个代码片段来展示如何实现? –

相关问题