当我有:
<UserControl.Resources>
<Style x:Key="itemstyle" TargetType="{x:Type ListViewItem}">
<EventSetter Event="MouseDoubleClick" Handler="HandleDoubleClick" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</UserControl.Resources>
<Grid>
<ListView ItemContainerStyle="itemstyle" Name="listView1" >
<ListView.View>
<GridView>
... etc
背后的代码
protected void HandleDoubleClick(object sender, MouseButtonEventArgs e)
{
T item = (T)(((ListViewItem)sender).Content);
// item is the row item that was double clicked on
}
一切都很好。
现在我需要在代码背后做同样的事情。这就是我的成果:
public Constructor(){
listview.AddHandler(
ListViewItem.MouseDoubleClickEvent,
new MouseButtonEventHandler(HandleDoubleClick)
);
}
protected void HandleDoubleClick(object sender, MouseButtonEventArgs e)
{
T item = (T)(((ListViewItem)sender).Content);
// error cause the sender is the listview
}
当我双击listview的任何部分而不仅仅是listviewItem时,该事件将触发。此外,我希望发件人是ListViewItem,它不是。发件人实际上是列表视图。我尝试过的事情:
1)因为发件人是列表视图,所以我尝试将事件创建为:
listview.AddHandler(
// I use PreviewMouseDoubleClickEvent instead of MouseDoubleClickEvent because of the way the events bubles
ListViewItem.PreviewMouseDoubleClickEvent,
new MouseButtonEventHandler(HandleDoubleClick)
);
我收到的错误是发件人是listview
2)而不是:
T item = (T)((ListViewItem)sender).Content;
我做:
T item = (T)(listview.selectedItem);
这个问题是,如果用户双击列表视图中不是行的任何内容,它将返回当前所选项目
为什么我的代码不起作用?我做错了什么?
答案 0 :(得分:2)
我认为你应该使用附加行为,因为
你做的是什么:
从上图中可以看出,此CommandBehavior
类将命令链接到控件。
在上面的情况下,它是一个按钮库,但是我们要创建一个ListViewItem
你将需要prism这个,因为它继承自的CommandBehaviorBase是该库的一部分。你可以得到它here(但是对于这个例子你只需要Prism.Commands dll)
命名约定表示您应该以
格式命名此CommandBehavior [X][Y]CommandBehavior
X - 我们绑定命令的控件的名称(在本例中为ListViewItem)
Y - 用户执行的将导致命令发生的操作(在本例中为DoubleClick)
下面是代码:
public class ListViewItemDoubleClickCommandBehaviour : CommandBehaviorBase<ListViewItem>
{
public ListViewItemDoubleClickCommandBehaviour(ListViewItem controlToWhomWeBind)
: base(controlToWhomWeBind)
{
controlToWhomWeBind.MouseDoubleClick += OnDoubleClick;
}
private void OnDoubleClick(object sender, System.Windows.RoutedEventArgs e)
{
ExecuteCommand();
}
}
这个类将包含所有双击命令。
它被称为doubleclick,因为它代表双击的实际行为。其他类型的操作(比如你想要一个文本框中按钮的命令)将拥有自己的类及其命令,命令参数和行为,然后我们就可以访问了。
这些命令是ICommand
类型的依赖项属性(我假设你已经实现了这个接口,因为你需要它用于MVVM)
命令本身的一个依赖属性,一个用于命令所需的参数(在这种情况下,您可能会将所选项目用作参数)
此类具有ListViewItemDoubleClickCommandBehavior的实例作为依赖项属性。这是在绑定到控件的命令和ListViewItemDoubleClickCommandBehaviour中的双击事件之间创建链接的方式。我们使用一些CommandBehaviorBase的魔术方法来创建行为并将命令传递给它。
OnSetCommand和OnSetCommandParameter回调用于将Behavior连接到命令。每次命令更改时,我们都会将其设置为要运行的行为的新命令。这些回调被注册到构造函数的PropertyMetadata部分中的DependencyProperties。每当依赖项属性发生更改时,都会触发它们。
这是该类的代码:
public static class DoubleClick
{
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached(
"Command",
typeof(ICommand),
typeof(DoubleClick),
new PropertyMetadata(OnSetCommandCallback));
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.RegisterAttached(
"CommandParameter",
typeof(object),
typeof(DoubleClick),
new PropertyMetadata(OnSetCommandParameterCallback));
private static readonly DependencyProperty DoubleClickCommandBehaviorProperty =
DependencyProperty.RegisterAttached(
"DoubleClickCommandBehavior",
typeof(ListViewItemDoubleClickCommandBehaviour),
typeof(DoubleClick),
null);
public static void SetCommand(ListViewItem controlToWhomWeBind, ICommand value)
{
controlToWhomWeBind.SetValue(CommandProperty, value);
}
public static ICommand GetCommand(ListViewItem controlToWhomWeBind)
{
return (ICommand)controlToWhomWeBind.GetValue(CommandProperty);
}
public static void SetCommandParameter(ListViewItem controlToWhomWeBind, ICommand value)
{
controlToWhomWeBind.SetValue(CommandParameterProperty, value);
}
public static ICommand GetCommandParameter(ListViewItem controlToWhomWeBind)
{
return (ICommand)controlToWhomWeBind.GetValue(CommandParameterProperty);
}
private static void OnSetCommandCallback(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs e)
{
ListViewItem controlToWhomWeBind= dependencyObject as ListViewItem;
if (controlToWhomWeBind!= null)
{
ListViewItemDoubleClickCommandBehaviour behavior = GetOrCreateBehavior(controlToWhomWeBind);
behavior.Command = e.NewValue as ICommand;
}
}
private static void OnSetCommandParameterCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
ListViewItem controlToWhomWeBind= dependencyObject as ListViewItem;
if (controlToWhomWeBind!= null)
{
ListViewItemDoubleClickCommandBehaviour behavior = GetOrCreateBehavior(controlToWhomWeBind);
behavior.CommandParameter = e.NewValue;
}
}
private static ListViewItemDoubleClickCommandBehaviour GetOrCreateBehavior(
ListViewItem controlToWhomWeBind)
{
ListViewItemDoubleClickCommandBehaviour behavior =
controlToWhomWeBind.GetValue(DoubleClickCommandBehaviorProperty) as
ListViewItemDoubleClickCommandBehaviour;
if (behavior == null)
{
behavior = new ListViewItemDoubleClickCommandBehaviour (controlToWhomWeBind);
controlToWhomWeBind.SetValue(DoubleClickCommandBehaviorProperty, behavior);
}
return behavior;
}
}
我知道这看起来很像复杂的代码,但是一旦你经常使用它就会变成一个简单的模式,并且它会从视图模型中抽象出所有复杂性,因此命令与控件的绑定看起来非常简单
既然咕噜咕噜的工作结束了,我们就可以轻松完成。
创建命令
我假设你熟悉命令,你可以像往常一样创建命令:
public ICommand DisplaySelectedItemCmd { get; protected set; }
//This method goes in your constructor
private void InitializeCommands()
{
//Initializes the command
this.DisplaySelectedItemCmd = new RelayCommand(
(param) =>
{
this.DisplaySelectedItem((object)param);
},
(param) => { return this.CanDisplaySelectedItem; }
);
}
//The parameter should be your listview's selected item. I have no idea what type it is so I made it an object
public void DisplaySelectedPolicy(object selectedListViewItem)
{
//Code to perform when item is double clicked
}
private bool CanDisplaySelectedPolicy
{
get
{
return true; //Change this bool if you have any reason to disable the double clicking, as this bool basically is linked to the double click command firing.
}
}
在xaml中创建绑定
现在是美丽的一部分。 首先添加xml命名空间:
xmlns:commands="clr-namespace:CommandHandling"
然后绑定到ListViewItem
<Style TargetType="{x:Type ListViewItem}" x:Key="{x:Type ListViewItem}" >
<Setter Property="commands:DoubleClick.Command" Value="{Binding Path=bleh}"/>
</Style>
并完成。
如果这不起作用,请告诉我。 (如果你愿意的话,任何读这篇文章的人都可以请你帮忙)
u_u
答案 1 :(得分:0)
在xaml中,您将事件处理程序附加到ListViewItem,而在后面的代码中将它附加到ListView本身。这就是为什么你会有不同的行为。如果您想在后面的代码中执行相同操作,则必须在项集合中循环al项,并将每个项的DoubleClick事件绑定到您的处理程序。
如果没有真正的理由在代码中执行此操作,我会选择适合MVVM模式的xaml方法,以便在后面的代码中尽可能少地保留代码。
答案 2 :(得分:0)
除非您想要在UserControl中使用命名内容,否则不要理解为什么要在代码中执行此操作,以便将其更改为自定义控件。尝试在后面的代码中重复你的xaml代码,即为ListViewItem创建一个样式并将其设置为listview的ItemContainerStyle。
答案 3 :(得分:0)
搞清楚!!我确信它应该与双击一样......
在xaml中我有:
<ListView IsSynchronizedWithCurrentItem="True" Name="listView" Margin="32,158,66,0" VerticalAlignment="Top">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<EventSetter Event="PreviewMouseUp" Handler="itemClicked"></EventSetter>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
... etc
我可以用c#在后面的代码上创建相同的东西:
EventSetter ev = new EventSetter();
ev.Event = ListViewItem.PreviewMouseUpEvent;
ev.Handler = new MouseButtonEventHandler(itemClicked);
Style myStyle = new Style();
myStyle.TargetType = typeof(ListViewItem);
myStyle.Setters.Add(ev);
listView.ItemContainerStyle = myStyle;
...
void itemClicked(object sender, MouseButtonEventArgs e)
{
// item was licked in listview implement behavior in here
}