如何从GridViewItem点击事件(XAML)执行命令

如何从GridViewItem点击事件(XAML)执行命令,xaml,winrt-xaml,windows-8.1,Xaml,Winrt Xaml,Windows 8.1,我试图在我的Windows8.1商店应用程序(XAML)中遵循MVVM模式 我希望在UI中单击/点击GridViewItem时导航到新视图。我希望这样做不需要代码隐藏事件来提高可测试性(使用MVVM Light) 为了允许我的UI绑定到视图模型命令,我一直在查看通过添加引用->窗口->扩展添加的Microsoft行为SDK(XAML) “我的视图”中的以下代码可以编译,但当我点击“网格视图”项时会崩溃。不幸的是,它没有提供什么帮助&只是抛出了一个未处理的win32异常[3476] 谁能帮我解释一

我试图在我的Windows8.1商店应用程序(XAML)中遵循MVVM模式

我希望在UI中单击/点击GridViewItem时导航到新视图。我希望这样做不需要代码隐藏事件来提高可测试性(使用MVVM Light)

为了允许我的UI绑定到视图模型命令,我一直在查看通过添加引用->窗口->扩展添加的Microsoft行为SDK(XAML)

“我的视图”中的以下代码可以编译,但当我点击“网格视图”项时会崩溃。不幸的是,它没有提供什么帮助&只是抛出了一个未处理的win32异常[3476]

谁能帮我解释一下这个问题吗

使用的名称空间是

xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"


<GridView x:Name="itemGridView"
                      AutomationProperties.AutomationId="ItemGridView"
                      AutomationProperties.Name="Grouped Items"            
                      ItemsSource="{Binding Source={StaticResource GroupedSource}}"                         
                      IsSwipeEnabled="True"
                      IsTapEnabled="True">

                <GridView.ItemTemplate>
                    <DataTemplate>
                        <Grid Margin="0"
                              Height="230">
                            <StackPanel Orientation="Vertical"
                                        HorizontalAlignment="Stretch">
                                <Image Source="{Binding Image}"                                  
                                       Stretch="UniformToFill"
                                       HorizontalAlignment="Center"
                                       VerticalAlignment="Center"
                                       />
                                <StackPanel VerticalAlignment="Bottom"
                                            Height="45"
                                            Margin="0,-45,0,0">
                                    <StackPanel.Background>
                                        <SolidColorBrush Color="Black" 
                                                         Opacity="0.75" 
                                                         />
                                    </StackPanel.Background>
                                    <TextBlock FontSize="16"
                                               Margin="2"
                                               Text="{Binding Name}"
                                               TextWrapping="Wrap"
                                               VerticalAlignment="Bottom"
                                               />
                                </StackPanel>
                            </StackPanel>

                            <interactivity:Interaction.Behaviors>
                                <core:EventTriggerBehavior EventName="Tapped">
                                    <core:InvokeCommandAction Command="{Binding DataContext.SummaryCatagorySelectedCommand, ElementName=LayoutRoot}" />
                                </core:EventTriggerBehavior>                                                                        
                            </interactivity:Interaction.Behaviors>                                                                                             
                        </Grid>
                    </DataTemplate>
                </GridView.ItemTemplate>
xmlns:interactivity=“使用:Microsoft.Xaml.interactivity”
xmlns:core=“使用:Microsoft.Xaml.Interactions.core”
编辑。根据要求,我添加了视图模型,其中专门包含我想从我的行为中触发的命令

public class ViewModel : ViewModelBase
{
    public RelayCommand<string> SummaryCatagorySelectedCommand { get; set; }

    public ViewModel()
    {
        //
    }
}
public类ViewModel:ViewModelBase
{
public RelayCommand SummaryCatagorySelectedCommand{get;set;}
公共视图模型()
{
//
}
}

我猜,当你点击任何你更改的项目时,我选择了编辑项。您可以绑定(Mode=TwoWay)SelectedItem并在属性的Set()中引发所需的操作

或者,您可以使用类似的内容,并将其用作GridView的依赖项属性

public class GridViewItemClickCommand
{
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command", typeof(ICommand),
        typeof(GridViewItemClickCommand), new PropertyMetadata
(null, CommandPropertyChanged));


    public static void SetCommand(DependencyObject attached, ICommand value)
    {
        attached.SetValue(CommandProperty, value);
    }


    public static ICommand GetCommand(DependencyObject attached)
    {
        return (ICommand)attached.GetValue(CommandProperty);
    }


    private static void CommandPropertyChanged(DependencyObject d,
                                    DependencyPropertyChangedEventArgs e)
    {
        // Attach click handler
        (d as GridView).ItemClick += gridView_ItemClick;
    }


    private static void gridView_ItemClick(object sender,
                                           ItemClickEventArgs e)
    {
        // Get GridView
        var gridView = (sender as GridView);


        // Get command
        ICommand command = GetCommand(gridView);


        // Execute command
        command.Execute(e.ClickedItem);
    }
}

如果您有任何问题,请询问:)

我发布了相同的问题,但我用另一种方式解决了它。我不会将行为放在datatemplate中,而是放在GridView中:

 <GridView x:Uid="Flow" 
                x:Name="PlacesGridView"
                Grid.Column="1" Grid.Row="2"
                ItemTemplate="{StaticResource YourDataTemplate}" 
                ItemsSource="{Binding YourSource}" >
                <Interactivity:Interaction.Behaviors>
                    <Behaviors:GoToDestinationOnSelected/>
                </Interactivity:Interaction.Behaviors>
            </GridView>

最简单的答案是告诉您在这种情况下不应该使用命令。首先,命令的价值在于它执行并将无法执行的情况反馈给交互式XAML控件。例如,当命令不可用时,该按钮将被禁用

但是由于您使用的是框架元素的tapped事件,因此基本上您只是使用控件,就好像它是一个简单的方法,而不是命令一样。当然,视图模型可以同时具有命令和方法。行为可以调用命令和方法

为此,对于您的解决方案来说,这里的最佳方案是改变您的方法,从在视图模型中调用命令开始。你的困难是1。该命令超出了数据模板和2的范围。命令参数在范围外线程上下文中传递

下面是我的建议,让你的生活更轻松,应用程序更简单

不要连接到项目的抽头事件。而是附加到gridview的itemclicked事件。当然,这意味着您需要在gridview上将IsItemClickEnabled设置为true。然后不要调用命令,这是您没有使用的开销,而是调用方法

这是viewmodel中方法的外观:

public async void ClickCommand(object sender, object parameter)
{
    var arg = parameter as Windows.UI.Xaml.Controls.ItemClickEventArgs;
    var item = arg.ClickedItem as Models.Item;
    await new MessageDialog(item.Text).ShowAsync()
}
方法的名称并不重要(我甚至把它称为一个命令来说明这一点),但签名确实重要。行为框架正在寻找具有零参数或两个对象类型参数的方法。方便的是,双参数版本获得转发给它的事件签名。在本例中,这意味着您可以使用包含已单击项的ItemClickEventArgs。这么简单

您的gridview也被简化了。您可以简单地将gridview的自然范围引用到外部viewmodel,而不必在数据上下文中强制作用域。它看起来像这样:

<GridView Margin="0,140,0,0" Padding="120,0,0,0" 
            SelectionMode="None" ItemsSource="{Binding Items}" 
            IsItemClickEnabled="True">
    <Interactivity:Interaction.Behaviors>
        <Core:EventTriggerBehavior EventName="ItemClick">
            <Core:CallMethodAction MethodName="ClickCommand" 
                TargetObject="{Binding Mode=OneWay}" />
        </Core:EventTriggerBehavior>
    </Interactivity:Interaction.Behaviors>

这是一个非常简单的解决方案,并且不会违反MVVM模式中的任何内容,因为它仍然将逻辑推出到您的独立且可测试的viewmodel中。它允许您有效地将行为用作事件到命令,但实际上使用了更简单的事件到方法模式。由于该行为首先不会将CanExecute值传递回控件,因此这实际上也简化了viewmodel

如果您想要做的是重用已经在其他地方使用过的现有命令(听起来像是1%edge的情况),那么您始终可以为此创建一个shell方法,在内部为您使用该命令

作为警告,Windows 8.1附带的RelayCommand没有正确实现ICommand,因为它没有在调用Execute之前先测试CanExecute。此外,类型化RelayCommand中的CanExecute逻辑不会将CommandParameter传递给处理程序。所有这些都不重要,这取决于您首先使用命令的人。但这对我很重要

这就是你的答案。更改为GridView.ItemClicked并从ViewModel.Command更改为ViewModel.Method。这使您的生活更加轻松,而且如果您想重用数据模板,您的XAML也更加可移植

祝你好运

在UWP(Window 10及更新版本)移动应用程序中,应用以下代码片段

<Interactivity:Interaction.Behaviors>
                                    <Core:EventTriggerBehavior EventName="ItemClick">
                                        <Core:EventTriggerBehavior.Actions>
                                            <Core:`enter code here`InvokeCommandAction Command="{Binding itemclick}"/>
                                        </Core:EventTriggerBehavior.Actions>
                                    </Core:EventTriggerBehavior>
                                </Interactivity:Interaction.Behaviors>

<Interactivity:Interaction.Behaviors>
                                    <Core:EventTriggerBehavior EventName="ItemClick">
                                        <Core:EventTriggerBehavior.Actions>
                                            <Core:`enter code here`InvokeCommandAction Command="{Binding itemclick}"/>
                                        </Core:EventTriggerBehavior.Actions>
                                    </Core:EventTriggerBehavior>
                                </Interactivity:Interaction.Behaviors>