Использование ListBox для навигации по TextBox с MVVM - PullRequest
2 голосов
/ 13 февраля 2011

Я пытаюсь отодвинуть следующую функцию listView_SelectionChanged от кода позади и обработать ее непосредственно внутри моего ViewModel (или непосредственно как XAML).И я надеялся, что у кого-то может быть лучшее представление о том, как это реализовать.

TextBox содержит разделы, например [Secion1], и для помощи в навигации у меня есть ListBox на стороне TextBox, которая содержит список всех разделов.Если вы щелкнете по одному из разделов, он автоматически перейдет к этой части текста.

Код в настоящее время выглядит примерно так:

XAML

ListBox ItemsSource="{Binding Path=Sections}" Name="listBox" 
                      SelectionMode="Single" Width="170" 
                      DisplayMemberPath="Section"
                      SelectionChanged="listView_SelectionChanged"/>

<TextBox Name="TextBox1" Text="{Binding Path=Source}"/>

Модель

public class SourceData
{
    public SourceData()
    {
        Sections = new List<SectionData>();
    }

    public String Source { get; set; }

    public List<SectionData> Sections { get; set; }
}

public class SectionData
{
    public int Line { get; set; }        // Line of the Section
    public String Section { get; set; }  // Section name (e.g. [Section1]
}

Код-позади

private void listView_SelectionChanged(object sender,
                               System.Windows.Controls.SelectionChangedEventArgs e)
{
    var test = (SectionData)listBox.SelectedItem; // Get Information on the Section

    if (test.Line > 0 && test.Line <= TextBox1.LineCount) // Validate
    {
        TextBox1.ScrollToLine(test.Line - 1); // Scroll to Line
    }
}

1 Ответ

3 голосов
/ 13 февраля 2011

В таких ситуациях я обычно создаю прикрепленное поведение (в вашем случае это будет поведение, которое позволит синхронизировать прокручиваемую строку текстового поля), добавляю свойство в ViewModel (SourceData), которое будет определять это присоединенное поведение и привязывать поведение к этому свойство.

Шаги, которые вы должны сделать в вашем случае (я полагаю, вы знаете, как создать вложенные свойства):

1) Создать прикрепленное поведение ScrolledLine для текстового поля. Он должен поддерживать как минимум one-way привязку. В обратном вызове присоединенного свойства вы прокрутите textBox (к которому привязано поведение) до line. Ниже вы найдете краткий пример того, как реализовать такое поведение.

2) Ваш SourceData должен быть расширен как минимум двумя свойствами: SelectedSection и ScrolledLine. ScrolledLine должно быть повышение PropertyChanged. SelectedSection сеттер должен измениться ScrolledLine:

private SectionData _selectedSection;
public SectionData SelectedSection
{
    get { return _selectedSection; }
    set 
    {
        _selectedSection = value;
        if (_selectedSection != null) SelectedLine = _selectedSection.Line;
    }
}

3) Свяжите свой взгляд с этими двумя новыми свойствами:

b ниже - пространство имен xml для вашего прикрепленного поведения от # 1

<ListBox ItemsSource="{Binding Path=Sections}" SelectionMode="Single" Width="170" DisplayMemberPath="Section" SelectedItem="{Binding SelectedSection, Mode=TwoWay}" />

<TextBox Text="{Binding Path=Source}" b:Behaviors.ScrolledLine="{Binding ScrolledLine}" />

4) Удалите ваш listView_SelectionChanged обработчик событий из вида. Ваше мнение не должно иметь никакого кода, кроме InitializeComponent отныне.

P.S .: Вот пример того, как должно выглядеть ваше прикрепленное поведение:

public class b:Behaviors
{
    #region Attached DP registration

    public static int GetScrolledLine(TextBox obj)
    {
        return (int)obj.GetValue(ScrolledLineProperty);
    }

    public static void SetScrolledLine(TextBox obj, int value)
    {
        obj.SetValue(ScrolledLineProperty, value);
    }

    #endregion

    public static readonly DependencyProperty ScrolledLineProperty=
    DependencyProperty.RegisterAttached("ScrolledLine", typeof(int), typeof(Behaviors), new PropertyMetadata(ScrolledLine_Callback));

    // This callback will be invoked when 'ScrolledLine' property will be changed. Here you should scroll a textbox
    private static void ScrolledLine_Callback(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        var textbox = (TextBox) source;

        int newLineValue = (int)e.NewValue;

        if (newLineValue > 0 && newLineValue <= textBox.LineCount) // Validate
            textbox.ScrollToLine(newLineValue - 1); // Scroll to Line
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...