如何将命令绑定到 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}" />
在这种情况下,您的子项目作为参数传递给您的命令,因此它也应该可以解决您在父模型中定义的命令的问题。
我看到了一些关于 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}" />
在这种情况下,您的子项目作为参数传递给您的命令,因此它也应该可以解决您在父模型中定义的命令的问题。