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

时间:2015-05-10 10:57:42

标签: c# xaml windows-phone-8.1

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

我有一个从代码绑定的datatemplate(它是一个hub datatemplate,我有混合的静态和动态hubsections,因此需要从代码中设置此datatemplate。)

此datatemplate在单独的xaml文件中定义,它包含一个列表框(或listview),其中包含为项目定义的另一个datatemplate。

我需要在项目的tap或listbox selectionchanged上绑定命令(或等效的东西)。但是,模板中定义的tap事件未被调用,因此我想到在UI元素上绑定命令,但这些似乎不支持Commands和交互触发器。

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

在下面的示例中,我没有得到事件Item_Tapped和ListBox_SelectionChanged,我反正希望将其中一个绑定到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;}
}

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; }}
}

我的(临时)解决方案是使用itemtemplate中的按钮:

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

1 个答案:

答案 0 :(得分:9)

您可以使用行为SDK
在Visual Studio中,转到“工具 - &gt;扩展和更新'并安装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类中定义了Command时,此代码才有效。如果要绑定到父元素Command,可以尝试这样的(未测试):

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

但我会优先对你的ItemModel班级发出指令 修改:没有行为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}" />

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