C# 如何将命令绑定到StackPanel或Grid tap事件?

C# 如何将命令绑定到StackPanel或Grid tap事件?,c#,xaml,windows-phone-8.1,C#,Xaml,Windows Phone 8.1,我已经看到了一些关于WP8或其他的答案,但是似乎WP8.1中没有触发器(或者我遗漏了什么?) 我从代码中绑定了一个datatemplate(它是一个hub datatemplate,并且我混合了静态和动态HubSection,因此需要从代码中设置此datatemplate) 此datatemplate在单独的xaml文件中定义,它包括一个listbox(或listview)以及为项目定义的另一个datatemplate 我需要在项目的点击或列表框selectionchanged(或其他等效项)上

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

我从代码中绑定了一个datatemplate(它是一个hub datatemplate,并且我混合了静态和动态HubSection,因此需要从代码中设置此datatemplate)

此datatemplate在单独的xaml文件中定义,它包括一个listbox(或listview)以及为项目定义的另一个datatemplate

我需要在项目的点击或列表框selectionchanged(或其他等效项)上绑定一个命令。但是,模板中定义的tap事件没有被调用,因此我考虑在UI元素上绑定一个命令,但是这些似乎不支持命令,也不支持交互触发器

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

在下面的示例中,我既没有点击事件项,也没有更改列表框的选择,我还是希望将其中一个绑定到viewmodel中的命令

<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;}
}
HubSection hs=新的HubSection()
{
ContentTemplate=Application.Current.Resources[HUBSECTION\u TEMPLATE]作为DataTemplate,
DataContext=模型,
Tag=model.UniqueId,
};
轮毂部分插入(firstSectIdx+1,hs);
公共类模型
{
公共Guid唯一ID{get;set;}
公共列表MyNodes{get;set;}
}
公共类项目模型
{
公共字符串MyText{get;set;}
}
PS:ItemModel是在另一个程序集中定义的,因此不应进行编辑(如果可能,该命令应位于Model类中)

---编辑---

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

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; }}
}
公共类模型
{
公共Guid唯一ID{get;set;}
公共列表MyNodes{get;set;}
公共ICommand MyCommand{get;set;}
}
公共类项目模型
{
模型(u)模型,;
公共项目模型(模型m){u模型=m;}
公共字符串MyText{get;set;}
public ICommand MyCommand{get{return\u Model.MyCommand;}}
}
我的(临时)解决方案是使用itemtemplate中的按钮:

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

您可以使用行为SDK
在VisualStudio中,转到“工具->扩展和更新”并安装行为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



编辑:无行为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 
    IsItemClickEnabled="True" 
    helpers:ItemClickCommand.Command="{Binding YourCommand}"
    ItemsSource="{Binding MyNodes}"
    ItemTemplate="{StaticResource YourDataTemplate}" />
然后,您的ListView将如下所示:

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 
    IsItemClickEnabled="True" 
    helpers:ItemClickCommand.Command="{Binding YourCommand}"
    ItemsSource="{Binding MyNodes}"
    ItemTemplate="{StaticResource YourDataTemplate}" />


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

与其直接使用StackPanel,不如将其包装在样式化按钮中?这样,您就可以使用按钮命令绑定来拦截单击。另一件事,你要求项目点击或选择改变。请注意,这两种行为不同,如果您两次选择同一项目,单击将触发,但选择更改不会触发。关于行为,这并不重要,因为我正在构建类似于文件浏览器的东西,因此,如果点击该项目,应该会发生一些事情,而不会发生两次。如果我找不到任何其他选项,我将以使用按钮结束,但我真的不喜欢在不应该使用按钮的情况下使用按钮。我已编辑了您的标题。请参阅“”,其中一致意见是“不,他们不应该”。我同意“一般”,但这是一个非常具体的问题,因为我能够在其他XAML平台上处理这个问题,而不是在WP8.1上。这就是为什么我在标题中指定了它,因为它很重要。这就是我一直在寻找的,但是我找不到它。我使用的是Visual Studio 2015 RC,这可能就是为什么它不能作为扩展提供的原因?我使用的是VS 2013,所以我不知道是什么导致了这个问题。我发布了另一个没有行为SDK的解决方案。希望它能有所帮助。我看到了,我还没有时间尝试它,但是它看起来像是一个很好的解决方案,它或多或少是我一直在寻找的解决方案,谢谢!)出于我不理解的原因,ItemClickCommand注册到事件中,但在应该引发事件时不会触发(从未调用OnItemClick)。因此,我的临时解决方案是一个itemtemplate,带有封装内容的按钮,绑定到指向ItemModel的命令,这本身就是来自集合模型的重定向<代码>公共类模型{public Guid UniqueId{get;set;}公共列表MyNodes{get;set;}公共ICommand MyCommand{get;set;}}公共类ItemModel{Model}模型{Model}公共项模型(Model m){u Model=m;}公共字符串MyText{get;set;}公共ICommand MyCommand{get{return\u Model.MyCommand;}}}