gpt4 book ai didi

wpf - ControlTemplate InputBinding 中的 ListBoxItem MouseBinding 不起作用 MVVM

转载 作者:行者123 更新时间:2023-12-01 20:00:08 26 4
gpt4 key购买 nike

我希望对某人来说这是一个明显的问题。我希望当用户双击列表框中的 ListBoxItem 时触发编辑命令。我之前已经在用户控件中完成了此操作,但想直接在 VIEW 中完成此操作,因为它是一个足够简单的列表框。但它不会连接。

这是列表框:

<ListBox SelectedItem="{Binding DataQuerySortSelected}"
ItemContainerStyle="{StaticResource SortListItemStyle}"
ItemsSource="{Binding DataQueryHolder.DataQuerySorts}">

<ListBox.InputBindings>
<KeyBinding Key="Delete" Command="{Binding DataQuerySortDelete}" />
</ListBox.InputBindings>

<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="AllowDrop" Value="True" />
<EventSetter Event="PreviewMouseMove" Handler="DragDropListBoxItem_PreviewMouseMoveEvent" />
<EventSetter Event="Drop" Handler="DragDropListBoxItem_Drop" />
</Style>

</ListBox.Resources>
</ListBox>

请注意,顶层的删除键绑定(bind)工作得很好。这是引用的样式(作为单独的 ResourceDictionary 引入,但将样式内联没有区别):

<Style x:Key="SortListItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="MainBorder">
<ContentPresenter>
<ContentPresenter.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding DataQuerySortEdit}" />
</ContentPresenter.InputBindings>
</ContentPresenter>

<Border.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding DataQuerySortEdit}" />
</Border.InputBindings>
</Border>

<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="MainBorder" Value="Yellow" Property="Background" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

我将鼠标绑定(bind)放在两个地方只是为了看看它是否有所不同,但事实并非如此。那里没有任何接线。其他一切都按预期进行。如果我在 View 中创建一个普通按钮并将其指向 DataQuerySortEdit 命令,它将按预期工作。

我错过了什么吗?感谢您的帮助。

<小时/>

编辑:只是添加一些更多信息来响应 J 的响应。我为 ControlTemplate 的边框提供了相对于最近的列表框的绑定(bind),并为列表框指定了名称,以便输出将确认它会找到它。这是输出窗口:

System.Windows.Data Error: 40 : BindingExpression path error: 'DataQuerySortEdit' property not found on 'object' ''DataQuerySort' (HashCode=7641038)'. BindingExpression:Path=DataQuerySortEdit; DataItem='DataQuerySort' (HashCode=7641038); target element is 'MouseBinding' (HashCode=65119131); target property is 'Command' (type 'ICommand')
System.Windows.Data Error: 40 : BindingExpression path error: 'DataQuerySortEdit' property not found on 'object' ''DataQuerySort' (HashCode=50439840)'. BindingExpression:Path=DataQuerySortEdit; DataItem='DataQuerySort' (HashCode=50439840); target element is 'MouseBinding' (HashCode=3649016); target property is 'Command' (type 'ICommand')
System.Windows.Data Error: 40 : BindingExpression path error: 'DataQuerySortEdit' property not found on 'object' ''DataQuerySort' (HashCode=65588106)'. BindingExpression:Path=DataQuerySortEdit; DataItem='DataQuerySort' (HashCode=65588106); target element is 'MouseBinding' (HashCode=35717517); target property is 'Command' (type 'ICommand')
System.Windows.Data Error: 40 : BindingExpression path error: 'DataQuerySortEdit' property not found on 'object' ''DataQuerySort' (HashCode=32836053)'. BindingExpression:Path=DataQuerySortEdit; DataItem='DataQuerySort' (HashCode=32836053); target element is 'MouseBinding' (HashCode=66172851); target property is 'Command' (type 'ICommand')
System.Windows.Data Error: 40 : BindingExpression path error: 'DataQuerySortEdit' property not found on 'object' ''ListBox' (Name='SortListBox')'. BindingExpression:Path=DataQuerySortEdit; DataItem='ListBox' (Name='SortListBox'); target element is 'MouseBinding' (HashCode=28263486); target property is 'Command' (type 'ICommand')
System.Windows.Data Error: 40 : BindingExpression path error: 'DataQuerySortEdit' property not found on 'object' ''ListBox' (Name='SortListBox')'. BindingExpression:Path=DataQuerySortEdit; DataItem='ListBox' (Name='SortListBox'); target element is 'MouseBinding' (HashCode=27134857); target property is 'Command' (type 'ICommand')
System.Windows.Data Error: 40 : BindingExpression path error: 'DataQuerySortEdit' property not found on 'object' ''ListBox' (Name='SortListBox')'. BindingExpression:Path=DataQuerySortEdit; DataItem='ListBox' (Name='SortListBox'); target element is 'MouseBinding' (HashCode=7437765); target property is 'Command' (type 'ICommand')
System.Windows.Data Error: 40 : BindingExpression path error: 'DataQuerySortEdit' property not found on 'object' ''ListBox' (Name='SortListBox')'. BindingExpression:Path=DataQuerySortEdit; DataItem='ListBox' (Name='SortListBox'); target element is 'MouseBinding' (HashCode=58400697); target property is 'Command' (type 'ICommand')

因此,第二次尝试绑定(bind)(我猜是边框输入绑定(bind)中的绑定(bind))确实可以正常使用正确的列表框,但仍然找不到 ICommand。我尝试对窗口、包含列表的网格等进行相对查找,但仍然无法将其连接起来。我还尝试像 J 提到的那样将相对搜索直接放在 MouseBindings 中,它们会导致相同的错误。

<小时/>

EDIT2:这是 ViewModel 中的命令和属性,使用 MVVMLight

public DataQuerySort DataQuerySortSelected
{
get { return _DataQuerySortSelected; }
set { NotifySetProperty(ref _DataQuerySortSelected, value, () => DataQuerySortSelected); }
}
private DataQuerySort _DataQuerySortSelected;


public RelayCommand DataQuerySortEdit
{
get { return new RelayCommand(_DataQuerySortEdit, CanDataQuerySortEdit); }
}
private void _DataQuerySortEdit()
{
DataQuerySortHolder = DataQuerySortSelected.Copy();
DataQuerySortEditMode = EditMode.Edit;
}
private bool CanDataQuerySortEdit()
{
return DataQuerySortSelected != null;
}

取出 CanDataQuerySortEdit 没有什么区别。我知道一切正常,因为如果我创建一个按钮并指向它,它就会正常工作。如果我还在 ListBox 中为鼠标创建一个输入绑定(bind),例如可以使用的删除键 - 当然,只要我在 ListBoxItems 外部单击即可。

EDIT3:这是 View 本身的一部分,包括类、数据上下文和资源。我尝试将相对绑定(bind)设置为“{x:Type Window}”和“{x:Type l:ToolkitWindowBase}”。 ToolkitWindowBase 直接扩展 Window。 frmDataBrowserViewModel 扩展了一个名为 ToolkitViewModelBase 的类,该类从 MVVMLight 扩展了 ViewModelBase:

<l:ToolkitWindowBase x:Class="GISToolkit.frmDataBrowser"  x:Name="mainWindow" Icon="Images/favicon.ico" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d"
xmlns:l="clr-namespace:GISToolkit;assembly="
xmlns:lc="clr-namespace:GISToolkit.Controls;assembly="
xmlns:ls="clr-namespace:GISToolkit.Settings;assembly="
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:xctk="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
xmlns:xctkp="clr-namespace:Xceed.Wpf.Toolkit.Primitives;assembly=Xceed.Wpf.Toolkit"
Title="Solutions GIS Toolkit - Setup"
ResizeMode="CanResizeWithGrip" Foreground="White"
l:ControlBox.HasMaximizeButton="False" l:ControlBox.HasMinimizeButton="False" l:ControlBox.HasCloseButton="False"
Height="{Binding RunTimeHeight, Mode=TwoWay}"
Width="{Binding RunTimeWidth, Mode=TwoWay}" IsSettingsDirty="{Binding IsCurrentSettingsDirty}" IsEnabled="True">

<Window.DataContext>
<l:frmDataBrowserViewModel />
</Window.DataContext>

<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/DataBrowser.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>

..................
<l:ToolkitWindowBase />
<小时/>

EDIT4:以防万一有人仍在列表中,请帮我一个忙,创建一个名为“WpfMvvmApplication1”的新 WPF 项目,其中包含一个名为“BindingTestWindow”的窗口和一个名为“MainWindowViewModel”的 View 模型,然后为窗口放置(应该是简单的剪切/粘贴,除非您对文件/项目使用不同的名称):

<Window x:Class="WpfMvvmApplication1.BindingTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:WpfMvvmApplication1"
Title="BindingTestWindow" Height="300" Width="300">

<Window.DataContext>
<l:BindingTestViewModel />
</Window.DataContext>

<Grid>
<GroupBox Header="Sorting:" >
<Grid>
<ListBox Background="White" Name="SortListBox" ItemsSource="{Binding TestCollection}">

<ListBox.InputBindings>
<KeyBinding Key="Delete" Command="{Binding TestCommand}" />
</ListBox.InputBindings>

<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="AllowDrop" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="MainBorder" Padding="0" Margin="0">
<ContentPresenter />

<Border.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding TestCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</Border.InputBindings>
</Border>

<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="MainBorder" Value="Yellow" Property="Background" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
</ListBox>
</Grid>
</GroupBox>
</Grid>
</Window>

对于 VIEWMODEL:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Windows.Input;

namespace WpfMvvmApplication1
{
public class BindingTestViewModel : NotificationObject
{
public BindingTestViewModel()
{
TestCollection = new ObservableCollection<string>();
for (int i = 0; i < 10; i++ )
TestCollection.Add("test" + i);
}

public ICommand TestCommand { get { return new DelegateCommand(_TestCommand); } }

private void _TestCommand() { System.Diagnostics.Debugger.Break(); }

public ObservableCollection<string> TestCollection
{
get { return _TestCollection; }
set
{
_TestCollection = value;
RaisePropertyChanged(() => TestCollection);
}
}
private ObservableCollection<string> _TestCollection;
}

public class DelegateCommand : ICommand
{
private readonly Action _command;
private readonly Func<bool> _canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

public DelegateCommand(Action command, Func<bool> canExecute = null)
{
if (command == null)
throw new ArgumentNullException();
_canExecute = canExecute;
_command = command;
}

public void Execute(object parameter)
{
_command();
}

public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute();
}

}

public class NotificationObject : INotifyPropertyChanged
{
protected void RaisePropertyChanged<T>(Expression<Func<T>> action)
{
var propertyName = GetPropertyName(action);
RaisePropertyChanged(propertyName);
}

private static string GetPropertyName<T>(Expression<Func<T>> action)
{
var expression = (MemberExpression)action.Body;
var propertyName = expression.Member.Name;
return propertyName;
}

private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

public event PropertyChangedEventHandler PropertyChanged;
}
}

这里面没有别的东西。当输入绑定(bind)位于列表框内部时,它会给我绑定(bind)错误,但当输入绑定(bind)位于列表框本身时,则不会。看起来它应该可以工作,因为输出表明它确实在 FindAncestor 中找到了窗口。

最佳答案

尝试将命令绑定(bind)更改为以下代码。列表框项是列表框的可视子项,您需要正确连接数据上下文。我认为。注意窗口类型。将其更改为声明命令且列表框存在的顶级数据上下文。即:用户控件、窗口等...

<MouseBinding Gesture="LeftDoubleClick" Command="{Binding DataQuerySortEdit, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}}" /> 

当您运行应用程序时,您可以通过查看输出窗口来调试它,它会向您显示这样的绑定(bind)错误。

编辑 1:Mvvm Light 事件到命令

好吧,我完全忽略了您正在起诉 Mvvm Light 的事实。 MVVM-Light 有一个内置函数,用于将事件绑定(bind)到 View 模型上的命令。

将以下内容添加到您的 Windows 命名空间:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="http://www.galasoft.ch/mvvmlight"

现在更改列表框项目内的边框以包含以下内容:

<Border ...>
<i:Interaction.Triggers>
<i:EventTrigger EventName="LeftDoubleClick">
<cmd:EventToCommand Command="{Binding DataContext.DataQuerySortEdit, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Border>

Mvvm light 构建此功能是为了准确地满足您的需求。它允许您获取任何事件并将命令绑​​定到它。我使用它通过控件的丢失焦点事件等进行表单验证。

确保您的项目中有以下引用:

  • GalaSoft.MvvmLight.WPF45
  • GalaSoft.MvvmLight.Extras.WPF45
  • Microsoft.Expression.Interactions

希望这有帮助

编辑3:

只是最后的努力,如果您使用以下内容会怎样:

它将 Datacontext 添加到命令名称中。

关于wpf - ControlTemplate InputBinding 中的 ListBoxItem MouseBinding 不起作用 MVVM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19984055/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com