2
votes

I need to create a WPF ListBox that supports two features:

Content Converter Binding:
The items in the ListBox need to be passed to a converter that converts the items to a text format.

Display items in a way that lets users select and copy text from ListBox items
I need the text of each ListBox item to be selectable. Users want to use their mouse to drag-to-select parts of the elements so they can copy the text to their clipboard.

I implemented [this copy/paste solution][1] but it does not let a user select parts of the ListBox item text, rather it supports copying the entire text.

I'm able to create a ListBox using the converter, but I can not figure out how to put the converted text into a control that lets users select the displayed text. Here is what I have:

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

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

I've tried adding a TextBox to the DataTemplate as shown below...

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

... but this creates a runtime error caused by sending the wrong type of object to the converter. I know here I'm not setting up the converter binding properly, though I don't have a good grasp on how I should setup the binding here or why this causes errors.

So, my question is:

What content container can I use to let users select text from the individual ListBox items?

Thank you for any help,
Charlie

EDIT

Here's the converter code...

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

EDIT 2

The following runtime error is throw when the ListBox is first initialized:

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

EDIT 3

The culprit is a line of code I'd omitted from the original snippet as I thought it was irrelevant - I've learned a good lesson along the way!

Extension Question

Why does the following snippet cause an error? How can I achieve the desired affect of making the textbox span the entire containing grid?

<TextBox Width="*"
         Text="{Binding Path=., Converter={StaticResource testFailItemConverter}}"/>
2
What other requirements does the ListBox have (selection, right click, etc.)? Can you show us your Converter code? Why not modify the Converter, or make a new one, to support the TextBlock?almulo
Added the Converter code in an edit. I'm not sure how I would modify it to support the TextBlock. There are no other requirements for the ListBox.itscharlieb
What's that runtime error you're getting? Whatever Itemize returns, the TextBlock should be able to show it as text (it uses ToString by default). Anyway, TextBlocks don't support text selection either, so this won't help you... Have you tried using a TextBox with IsReadOnly="True"?almulo

2 Answers

1
votes

Have You tried TextBox? You can select text inside textbox. Path have to be changed to Path=.

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

There is not much code to work with, but this code works for me:

xaml:

<Window x:Class="StackOverflowTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:s="clr-namespace:StackOverflowTest"
        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>

Model's code:

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

Converter's code:

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

Try this. TextBlocks don't support text selection, but TextBoxes do. You just have to make it read-only so the user can't modify the text, and change its border thickness and background so they look like labels:

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