我正在使用MVVM模式开发Windows应用商店应用(没有框架,只有原始MVVM)。
我有一个用户控件DropboxFileplanUserControl.xaml
,它有一个关联的视图模型DropboxFileplanViewModel.cs
。 DropboxFileplanUserControl
中嵌入了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 :(得分: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(带有一些abridgments):
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将能够响应。
第二种选择需要更多的探索,我现在必须运行。但希望这会让你前进。对不起,短暂的结局。如果需要,请回答问题。祝你好运!