使用ListBox导航带有MVVM的TextBox

时间:2011-02-13 11:52:18

标签: c# wpf mvvm

我试图将以下函数listView_SelectionChanged从代码隐藏中移除,并直接在我的ViewModel内(或直接作为XAML)处理它。我希望有人可能对如何实现这一点有更好的了解。

TextBox包含章节,例如[Secion1]并帮助导航我在TextBox一侧有一个ListBox,其中包含所有章节的列表。如果单击其中一个部分,它将自动跳转到文本部分。

代码目前看起来像这样:

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 个答案:

答案 0 :(得分:3)

在这种情况下,我通常会创建一个附加行为(在您的情况下,它将是一个允许同步文本框滚动行的行为),在ViewModel(SourceData)中添加属性,该属性将规定附加行为和绑定行为这个属性。

您应该做的步骤(我假设您知道如何创建附加属性):

1)为文本框创建附加行为ScrolledLine。它应该至少支持one-way绑定。在附加属性回调中,您将textBox(附加到哪个行为)滚动到line。您将在下面找到如何实现此类行为的快速示例。

2)您的SourceData应至少使用两个属性进行扩展:SelectedSectionScrolledLineScrolledLine应该提出PropertyChangedSelectedSection setter应更改ScrolledLine

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

3)将您的观点绑定到这两个新属性:

下面的

b是来自#1

的附加行为的xml-namespace
<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
    }
}