如何将命令绑定到 StackPanel 或 Grid 点击事件?

How to bind a command to StackPanel or Grid tap event?

我看到了一些关于 WP8 或其他的答案,但是 WP8.1 中似乎没有触发器(或者我遗漏了什么?)

我有一个从代码绑定的数据模板(它是一个集线器数据模板,我有静态和动态集线器部分的混合,因此需要从代码设置这个数据模板)。

此数据模板在单独的 xaml 文件中定义,它包括一个列表框(或列表视图)和为项目定义的另一个数据模板。

我需要在项目的点击或列表框选择更改(或类似的东西)上绑定命令。但是,模板中定义的点击事件没有被调用,因此我想到了在UI元素上绑定一个命令,但是这些似乎不支持命令,也没有交互触发。

关于如何处理的任何线索? :)

在下面的示例中,我没有得到事件 Item_Tapped 也没有 ListBox_SelectionChanged,无论如何我更愿意将其中之一绑定到视图模型中的命令。

<DataTemplate x:Key="HubSectionTemplate">
    <Grid>
        <ListBox ItemsSource="{Binding MyNodes}"
            SelectionChanged="ListBox_SelectionChanged">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Height="64" Tapped="Item_Tapped" >
                        <TextBlock Text="{Binding MyText}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</DataTemplate>

这是代码中的用法:

HubSection hs = new HubSection()
{
    ContentTemplate = Application.Current.Resources[HUBSECTION_TEMPLATE] as DataTemplate,
    DataContext = model,
    Tag = model.UniqueId,
};
Hub.Sections.Insert(firstSectIdx + 1, hs);


public class Model
{
    public Guid UniqueId {get;set;}
    public List<ItemModel> MyNodes {get;set;}
}

public class ItemModel
{
    public string MyText {get;set;}
}

PS:ItemModel 是在另一个程序集中定义的,因此不应编辑(如果可能,命令应在模型 class 中)

--- 编辑 ---

为了简化问题,我使用了以下模型:

public class Model
{
    public Guid UniqueId {get;set;}
    public List<ItemModel> MyNodes {get;set;}
    public ICommand MyCommand {get;set;}
}

public class ItemModel
{
    Model _Model;
    public ItemModel(Model m) {_Model = m; }
    public string MyText {get;set;}
    public ICommand MyCommand { get { return _Model.MyCommand; }}
}

我的(临时)解决方案是在项目模板中使用一个按钮:

    <ListView.ItemTemplate>
        <DataTemplate>
            <Button HorizontalAlignment="Stretch"  Command="{Binding TapCommand}" Height="64">
                <TextBlock Text="{Binding MyText}" />
            </Button>
        </DataTemplate>
    </ListView.ItemTemplate>

您可以使用 Behaviors SDK
在 Visual Studio 中转到 'Tools -> Extension and updates' 并安装 Behaviors SDK (XAML)。然后使用添加引用对话框在您的项目中引用它。
之后将以下名称空间添加到您的页面:

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

现在您可以使用以下语法注册事件,例如点击您的堆栈面板:

<DataTemplate>
    <StackPanel Orientation="Horizontal" Height="64">
        <TextBlock Text="{Binding MyText}" />
        <interactivity:Interaction.Behaviors>
            <core:EventTriggerBehavior EventName="Tapped">
                <core:InvokeCommandAction  Command="{Binding YourCommand}"/>
            </core:EventTriggerBehavior>
        </interactivity:Interaction.Behaviors>
    </StackPanel>
</DataTemplate>

然而,只有在您的 ItemModel class 中定义了您的命令时,此代码才有效。如果你想绑定到父元素Command,你可以这样尝试(未测试):

{Binding ElementName=LayoutRoot, Path=DataContext.ParentCommand}

但我更希望在你的 ItemModel class


上有命令 编辑: 没有行为 SDK 的解决方案:
如果您正在使用 ListView(或从 ListViewBase 继承的东西),您可以使用 ItemClick 事件。为了使其更具可重用性和 Mvvm 友好性,您可以像这样实现 DependencyProperty:

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

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

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

    private static void OnCommandPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var control = d as ListViewBase;
        if (control != null)
        {
            control.ItemClick += OnItemClick;                
        }

    }

    private static void OnItemClick(object sender, ItemClickEventArgs e)
    {
        var control = sender as ListViewBase;
        var command = GetCommand(control);

        if (command != null && command.CanExecute(e.ClickedItem))
        {
            command.Execute(e.ClickedItem);
        }
    }
}

那么您的 ListView 将如下所示:

<ListView 
    IsItemClickEnabled="True" 
    helpers:ItemClickCommand.Command="{Binding YourCommand}"
    ItemsSource="{Binding MyNodes}"
    ItemTemplate="{StaticResource YourDataTemplate}" />

在这种情况下,您的子项目作为参数传递给您的命令,因此它也应该可以解决您在父模型中定义的命令的问题。