Объедините текстовые поля в одно из ItemsSource

Есть ли способ объединить все текстовые поля, которые создает этот элемент управления, чтобы я мог выбрать их все как в одном текстовом поле или текстовом блоке? На данный момент я могу выделять текст только в одном текстовом блоке за раз.

<ItemsControl Background="WhiteSmoke" ItemsSource="{Binding SelectedItemNotes}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Vertical">
                <TextBox IsReadOnly="True" Background="Transparent" BorderThickness="0">
                    <TextBox.Text>
                        <MultiBinding StringFormat="{}{0} {1} - {3}">
                            <Binding Path="Timestamp" />
                            <Binding Path="UserName" />
                            <Binding Path="Notes" />
                        </MultiBinding>
                    </TextBox.Text>
                </TextBox>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

person Rob    schedule 02.11.2015    source источник


Ответы (1)


Что касается взаимодействия с выделением текста, вы хотите, чтобы пользователь взаимодействовал с текстом в нескольких текстовых полях, как если бы все они находились в одном большом многострочном текстовом поле: пользователь щелкает между четвертым и пятым символами в первом поле, перетаскивает непосредственно перед девятым символом в третьем поле и отпускает левую кнопку мыши. В результате выбирается все, что находится после четвертого символа в первом текстовом поле, выделяется все второе текстовое поле и выбираются первые восемь символов третьего.

Нет ничего, что могло бы сделать это за вас. Вы бы написали пользовательское взаимодействие с мышью. Я сделал выделение текста с помощью мыши, правда, только в одном элементе управления, и это сложнее, чем вы думаете, но это довольно круто, когда он наконец-то работает правильно.

Таким образом, вы должны настроить какое-то частное состояние в своем классе управления, чтобы события мыши знали, что пользователь участвует в этом взаимодействии с мега-выбором. Mousedown и перетаскивание в текстовое поле в ItemsControl запустило бы это, mouseup в одном из них завершило бы его.

В mousemove вам нужно будет установить SelectionStart / SelectionEnd для каждого текстового поля между тем, с которого вы начали, и тем, с которым вы закончили. Для того, с которым вы закончили (если это не первый), вам нужно будет написать собственный код, чтобы узнать, над каким символом находится мышь, и программно установить SelectionStart и SelectionEnd.

Не забывайте, что пользователь может перетаскивать выделение «вверх» из TextBox 2 в TextBox 0. Вам нужно знать, в каком направлении происходит выделение.

Как только вы узнаете, какие текстовые поля находятся в вашем выборе, напишите свойство, которое перечислит их. Учитывая, что, как только у них будет выбран соответствующий текст, легко получить полный текст выделения:

//  In order of first in UI to last, regardless of "selection direction"
protected IEnumerable<TextBox> MegaSelectionTextBoxes {
    get {
        //  Whatever -- might be a good idea to keep them 
        //  in a List<TextBox> or ObservableCollection<TextBox>
    }
}

//  The easy part
public String MegaSelectionText {
    get {
        return 
            String.Join("\n",
                        MegaSelectionTextBoxes.Select(
                            tb=>tb.SelectedText));
    }
}

Лично я бы не стал рассчитывать на то, что меньше чем за неделю все заработает правильно. Однако ваше определение «правильного» может быть гораздо более снисходительным.

Но я бы предпочел подход, который работает с XAML, а не пытаться его обойти.

Если бы это был я, если бы эта функция не была действительно критичной по какой-либо причине (а иногда и так), я бы пожертвовал частичным выделением в первом и последнем текстовых полях в выделении.

Я бы посмотрел на использование ListBox с множественным выбором, а не на ItemsControl, чтобы позволить пользователю выбирать элементы. Затем я привязал SelectedItems в ListBox к ObservableCollection в моей модели просмотра и написал команду в моей модели просмотра, которая делает все, что я хочу, с объединенным текстом всех выбранных элементов.

Другой вариант - использовать DataGrid с выбором нескольких ячеек. Это даст вам необходимое взаимодействие, хотя вам, возможно, придется поиграть в некоторые игры, чтобы заставить его выглядеть так, как вы хотите.

person 15ee8f99-57ff-4f92-890c-b56153    schedule 02.11.2015
comment
Выбор, возможно, был неподходящим словом для выбора. Я хочу иметь возможность выделить весь текст, например, щелкнув и перетащив, чтобы выделить весь текст в текстовом поле. Возможно ли это, используя список с множественным выбором? - person Rob; 02.11.2015
comment
@Rob Обновил мой ответ, чтобы разобраться в этом сценарии. Удачи! Это выглядит довольно забавной (читай: болезненной, но полезной) функцией, если есть веское экономическое обоснование для того, чтобы потратить на нее время. - person 15ee8f99-57ff-4f92-890c-b56153; 02.11.2015
comment
Я решил просто использовать StringBuilder и добавить все значения в мою ViewModel и вывести большую строку с новыми строками ... которая получает весь текст, который я хочу, в одном текстовом поле ... но возможно ли динамически изменить цвет определенных слов в строке? Без использования кода программной части с использованием привязки данных и MVVM? Мне нужно иметь возможность изменять цвет для каждого пользователя для каждой заметки. - person Rob; 03.11.2015
comment
Элемент управления WebBrowser может быть хорошей ставкой: создайте свойство ViewModel, которое возвращает цветной текст в формате HTML, и вставьте его в элемент управления WebBrowser. Нужно ли его редактировать в пользовательском интерфейсе? Если да, попробуйте RichTextBox.. Но если сделать его редактируемым, возникнут ужасные проблемы с выяснением того, какую заметку изменяет пользователь. Я бы оставил эту часть только для чтения, и если редактирование является требованием, сделайте это в другом месте. - person 15ee8f99-57ff-4f92-890c-b56153; 03.11.2015