3

誰かにとって明らかな問題であることを願っています。ユーザーが ListBox 内の ListBoxItem をダブルクリックしたときに Edit コマンドが起動するようにします。以前にユーザーコントロールでこれを行ったことがありますが、これは十分に単純なListBoxであるため、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>

最上位の Delete Key バインディングが正常に機能することに注意してください。参照されているスタイルは次のとおりです (個別の 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>

違いがあるかどうかを確認するために、マウスバインディングを2か所に配置しましたが、違いはありません. そこには配線が一切ありません。他のすべては期待どおりに機能します。ビューでプレーン ボタンを作成し、それを DataQuerySortEdit コマンドにポイントすると、期待どおりに機能します。

何か不足していますか?助けてくれてありがとう。


編集:Jの応答に応じて、さらに情報を追加するだけです。ControlTemplate の Border に最も近いリストボックスに相対的なバインディングを与え、リストボックスに名前を付けて、出力がそれを見つけることを確認できるようにしました。これは出力ウィンドウでした:

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')

したがって、バインドの 2 回目の試み (Border InputBinding のものと推測しています) は、適切なリストボックスを正常に処理しますが、それでも ICommand を見つけることができません。ウィンドウ、リストを含むGirdなどに対して相対検索を試みましたが、それでも配線できません。また、Jが相対検索をMouseBindingsに直接入れるように言及したように試みましたが、同じエラーが発生しました。


EDIT2:MVVMLightを使用したViewModelのコマンドとプロパティは次のとおりです

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 を取り出しても違いはありません。ボタンを作成してポイントすると機能するため、すべてが機能することを知っています。もちろん、ListBoxItemsの外側をクリックする限り、動作するDeleteキーのようなマウスのListBoxにinputbindingも作成すると。

EDIT3:これは、クラス、データコンテキスト、およびリソースを含むビュー自体の一部です。「{x:Type Window}」および「{x:Type l:ToolkitWindowBase}」になるように相対バインディングを試みました。ToolkitWindowBase は Window を直接拡張します。frmDataBrowserViewModel は、MVVMLight から ViewModelBase を拡張する ToolkitViewModelBase というクラスを拡張します。

<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: 誰かがまだリストに載っている場合に備えて、「BindingTestWindow」という単一のウィンドウと「MainWindowViewModel」というビューモデルを持つ「WpfMvvmApplication1」という新しい WPF プロジェクトを作成してください。ファイル/プロジェクトに別の名前を使用していない限り、カット/ペースト):

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

これには他に何もありません。inputbinding が listboxtiem 内にある場合はバインディング エラーが発生しますが、たとえばリストボックス自体にある場合は発生しません。出力がFindAncestorでウィンドウを見つけたと言っているので、うまくいくはずです。

4

3 に答える 3

0

私はこの問題をいじるのにかなりの時間を費やしました。うまくいっている結果といくつかの答えを組み合わせることができました。ListBox の Inputbindings は奇妙な動作をします。MiddleClick のように ListBox 自体で機能するものもあれば、項目に実装する必要があるものもあります。DataContext への J Kings Binding は、LisBoxItemStyle の ContentPresenter でトリックを行いました。

 <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">

                    <Border x:Name="Bd" 
                            BorderBrush="{TemplateBinding BorderBrush}" 
                            BorderThickness="{TemplateBinding BorderThickness}" 
                            Background="{TemplateBinding Background}" 
                            Padding="{TemplateBinding Padding}" 
                            SnapsToDevicePixels="true">

                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                            <ContentPresenter.InputBindings>
                                <MouseBinding Gesture="Ctrl+MiddleClick" 
                                              Command="{Binding  DataContext.MiddleClickCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
                                <MouseBinding Gesture="Ctrl+RightClick" 
                                              Command="{Binding DataContext.CtrlRightClickCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
                                <MouseBinding MouseAction="RightClick" 
                                              Command="{Binding DataContext.RightClickCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
                            </ContentPresenter.InputBindings>
                        </ContentPresenter>
                    </Border>
                    <ControlTemplate.Triggers>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsMouseOver" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.MouseOver.Background}"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.MouseOver.Border}"/>
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Selector.IsSelectionActive" Value="False"/>
                                <Condition Property="IsSelected" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Background}"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Border}"/>
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Selector.IsSelectionActive" Value="True"/>
                                <Condition Property="IsSelected" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Background}"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Border}"/>
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="TextElement.Foreground" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>

                </ControlTemplate>
            </Setter.Value>
        </Setter>  
于 2018-09-23T11:32:02.047 に答える