0

から継承するカスタムWPFコントロールがありListViewます。このコントロールのそれぞれListViewItemに他のそのようなコントロールを含めることができ、これは無限に続く可能性があります。

カスタムListViewサブクラスにはCommandBinding、切り取り、コピー、貼り付けの3つの機能と、ContextMenuこれらの各コマンドを発行する機能があります。すべてがトップレベルで期待どおりに機能します-切り取り、コピー、貼り付けができます。ただし、ネストされたListView子孫コントロールの1つを右クリックして、[貼り付け]を選択すると(他の2つは同じように機能しますが)、次のいずれかが発生します。

コントロールにListViewItemsが選択されていない場合、CommandExecutedイベントは上部ListViewをとして発生しCommandTargetます。コントロールに選択されている場合ListViewItem、すべてが正常に機能します。

これは既知の問題ですか?(まともな)回避策はありますか?ありがとう。

編集要求に応じて、ここに例があります:

カスタムListViewサブクラス:

public class MyListView : ListView
{
    public MyListView()
    {
        this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Copy,
            CopyCommand_Executed, CopyCutCommand_CanExecute));
        this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste,
            PasteCommand_Executed, PasteCommand_CanExecute));
        this.Background = new SolidColorBrush(Colors.Ivory);
    }

    MyListItem Binding 
    { 
        get { return this.DataContext as MyListItem; } 
    }

    private void CopyCutCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        if (e.Handled)
            return;

        e.CanExecute = (this.SelectedItems.Count > 0);
        e.Handled = true;
    }

    private void CopyCommand_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        if (e.Handled)
            return;

        if (this.SelectedItems.Count < 0)
            return; // Nothing selected

        List<MyListItem> items = new List<MyListItem>();
        foreach (MyListItem str in this.SelectedItems)
            items.Add(str);

        Clipboard.SetData("Stuff", items);

        e.Handled = true;
    }

    private void PasteCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        if (e.Handled)
            return;

        e.CanExecute = Clipboard.ContainsData("Stuff");
        e.Handled = true;
    }

    private void PasteCommand_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        if (e.Handled)
            return;

        MyListView lv = this;

        List<MyListItem> strings = Clipboard.GetData("Stuff") as List<MyListItem>;
        if (strings == null)
            return;

        foreach (MyListItem s in strings)
            this.Binding.Items.Add(s);

        e.Handled = true;
    }
}

単純なListViewItemバインディングクラス:

[Serializable]
public class MyListItem
{
    public MyListItem() { this.Items = new ObservableCollection<MyListItem>(); }
    public string Caption { get; set; }
    public ObservableCollection<MyListItem> Items { get; set; }
}

XAML for MyControl(コードビハインドなし)、それぞれの表現ListViewItem

<UserControl x:Class="TestNestedListView.MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:TestNestedListView">
    <Grid>
        <StackPanel Orientation="Vertical">
            <TextBlock Text="{Binding Path=Caption}" />
            <local:MyListView Padding="10" ItemsSource="{Binding Path=Items}"/>
        </StackPanel>
    </Grid>
</UserControl>

MainWindowXAML:

<Window x:Class="TestNestedListView.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestNestedListView"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:MyListItem}">
            <local:MyControl DataContext="{Binding}" />
        </DataTemplate>
        <Style TargetType="local:MyListView">
            <Setter Property="ItemContainerStyle">
                <Setter.Value>
                    <Style TargetType="{x:Type ListViewItem}">
                        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                        <Setter Property="VerticalContentAlignment" Value="Stretch" />
                    </Style>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <local:MyListView x:Name="lv" ItemsSource="{Binding Path=Items}">
        <local:MyListView.ContextMenu>
            <ContextMenu>
                <MenuItem Command="Copy" />
                <MenuItem Command="Paste" />
            </ContextMenu>
        </local:MyListView.ContextMenu>
    </local:MyListView>
</Window>

MainWindowコードビハインド:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        MyListItem root = new MyListItem();

        MyListItem item = new MyListItem() { Caption = "Item 1" };
        item.Items.Add(new MyListItem() { Caption = "Subitem 1.1" });
        root.Items.Add(item);
        root.Items.Add(new MyListItem() { Caption = "Item 2" });
        root.Items.Add(new MyListItem() { Caption = "Item 3" });
        root.Items.Add(new MyListItem() { Caption = "Item 4" });

        item = new MyListItem() { Caption = "Item 5" };
        item.Items.Add(new MyListItem() { Caption = "Subitem 5.1" });
        item.Items.Add(new MyListItem() { Caption = "Subitem 5.2" });

        root.Items.Add(item);

        lv.DataContext = root;
    }
}

これが実際に動作していることを確認するには、右クリックして任意のアイテムをコピーします。ListView次に、[アイテム2]の下の長方形(これは)を右クリックして、[貼り付け]をクリックします。新しいアイテムは、トップレベルの最後のアイテムとして貼り付けられることに注意してください。「サブアイテム1.1」の下の長方形を右クリックし、アイテムが「サブアイテム1.1」ではなく、「アイテム1」の子として貼り付けられていることに注意してください。

4

1 に答える 1

1

このリストによると、コマンドを適切に処理するには、ビューにフォーカスが必要です。フォームに入力したタイプの空のリストビューとテキストボックスを追加することで、この欠陥を確認しました。次に、テキストボックスにフォーカスしてクリップボードにある場合、リストビューでもテキスト貼り付けコマンドがアクティブになり、CanExecuteメソッドは起動されず、貼り付けコマンドを選択するとテキストボックスに貼り付けられます。これは確かにwpfのバグのように見えます。既知であることを示唆する記事はほとんど見つかりませんでしたが、そのチケットは見つかりませんでした。

WPFバグでContextMenusを無効にしました

ContextMenuアイテムが無効になっているのはなぜですか?

編集

シナリオの回避策として、次を追加するだけです。

protected override void OnMouseDown(MouseButtonEventArgs e)
{
    base.OnMouseDown(e);
    Dispatcher.BeginInvoke(new Func<bool>(Focus));
}

あなたのMyListViewクラスに。

于 2012-08-14T06:40:17.830 に答える