C# WPF:拖拽到 select 文本的列表框

C# WPF: Listbox with drag to select text

我需要创建一个支持两个功能的 WPF 列表框:

内容转换器绑定:
ListBox 中的项目需要传递给将项目转换为文本格式的转换器。

以允许用户 select 和从 ListBox 项目复制文本的方式显示项目
我需要每个 ListBox 项目的文本 selectable。用户希望使用鼠标拖动到元素的 select 部分,以便将文本复制到剪贴板。

我实施了 [这个 copy/paste 解决方案][1],但它不允许用户 select 列表框项目文本的一部分,而是支持复制整个文本。

我可以使用转换器创建一个列表框,但我不知道如何将转换后的文本放入一个控件中,让用户 select 显示文本。这是我拥有的:

<ListBox Name="FinishedTestErrorsListBox"
         FontSize="12"
         ItemsSource="{Binding Path=SelectedComparisonResult.TestFailItems}">

    <ListBox.ItemTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding Converter={StaticResource testFailItemConverter}}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>  

我试过向 DataTemplate 添加一个 TextBox,如下所示...

<TextBlock Text="{Binding Converter={StaticResource testFailItemConverter}}"/>  

... 但这会产生一个运行时错误,这是由于向转换器发送了错误类型的对象而引起的。我知道这里我没有正确设置转换器绑定,但我不太了解我应该如何在这里设置绑定或者为什么这会导致错误。

那么,我的问题是:

我可以使用什么内容容器让用户 select 来自各个 ListBox 项目的文本?

感谢您的帮助,
查理

编辑

这是转换器代码...

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
     ITestFailItem i = (ITestFailItem)value;
     return i.Itemize();
}  

编辑 2

首次初始化 ListBox 时抛出以下运行时错误:

An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll 

Additional information: Provide value on 'System.Windows.Baml2006.TypeConverterMarkupExtension' threw an exception

编辑 3

罪魁祸首是我从原始代码片段中省略的一行代码,因为我认为它无关紧要 - 我在此过程中吸取了很好的教训!

扩展问题

为什么以下代码片段会导致错误?我怎样才能达到使文本框跨越整个包含网格的预期效果?

<TextBox Width="*"
         Text="{Binding Path=., Converter={StaticResource testFailItemConverter}}"/>

试试这个。 TextBlock 不支持文本选择,但 TextBox 支持。您只需将其设置为只读,这样用户就无法修改文本,并更改​​其边框粗细和背景,使其看起来像标签:

<ListBox Name="FinishedTestErrorsListBox"
         FontSize="12"
         ItemsSource="{Binding Path=SelectedComparisonResult.TestFailItems}">
    <ListBox.Resources>
        <converter:TestFailItemConverter x:Key="testFailItemConverter" />
    </ListBox.Resources>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding Path=.,
                                    Converter={StaticResource testFailItemConverter},
                                    Mode=OneWay}"
                     BorderThickness="0"
                     Background="Transparent"
                     IsReadOnly="True"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>  

你试过TextBox吗?您可以 select 文本框内的文本。路径必须更改为 Path=.

<TextBox Text="{Binding Path=., Converter={StaticResource testFailItemConverter}}" />

没有多少代码可以使用,但这段代码对我有用:

xaml:

<Window x:Class="WhosebugTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:s="clr-namespace:WhosebugTest"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <s:TestFailItemConverter x:Key="testFailItemConverter" />
    </Window.Resources>
    <Grid>
        <ListBox Name="FinishedTestErrorsListBox"
         FontSize="12"
         ItemsSource="{Binding Path=SelectedComparisonResult.TestFailItems}">

            <ListBox.ItemTemplate>
                <DataTemplate>
                    <!--<ContentControl Content="{Binding Converter={StaticResource testFailItemConverter}}"/>-->
                    <TextBox Text="{Binding Path=., Converter={StaticResource testFailItemConverter}}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

模特代码:

public class Dummy
    {
        public ObservableCollection<string> TestFailItems { get; set; }

        public Dummy()
        {
            TestFailItems = new ObservableCollection<string>(new List<string> { "a", "b" });
        }
    }
    public class Model
    {
        public Dummy SelectedComparisonResult { get; set; }

        public Model()
        {
            SelectedComparisonResult = new Dummy();
        }
    }

转换器代码:

public class TestFailItemConverter: IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return "aa";
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value;
    }
}