You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF对话框中AvalonEditor的Find按钮绑定搜索(MVVM方式)

在WPF MVVM模式下通过按钮触发AvalonEditor的搜索功能

我懂你的需求——已经给AvalonEditor装好了SearchPanel,Ctrl+F能正常弹出搜索框,现在想在MVVM架构下,点击窗口上的Find按钮也能触发这个搜索功能,不想用传统的代码隐藏事件对吧?下面给你具体的实现步骤和代码,完全符合MVVM的规范:

第一步:先实现通用的RelayCommand(如果项目里还没有的话)

MVVM里需要自定义命令来绑定按钮动作,先写一个基础的RelayCommand类,后面ViewModel会用到:

public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;

    public event EventHandler CanExecuteChanged
    {
        add => CommandManager.RequerySuggested += value;
        remove => CommandManager.RequerySuggested -= value;
    }

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute?.Invoke(parameter) ?? true;
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

第二步:创建ViewModel并添加搜索命令

ViewModel里定义一个FindCommand,用来触发搜索面板的显示。我们把TextEditor实例作为命令参数传递,这样ViewModel不需要直接耦合视图元素,完全符合MVVM的分离原则:

using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Search;
using System.ComponentModel;
using System.Windows.Input;

public class MainWindowViewModel : INotifyPropertyChanged
{
    public ICommand FindCommand { get; }

    public MainWindowViewModel()
    {
        FindCommand = new RelayCommand(ExecuteFindCommand);
    }

    private void ExecuteFindCommand(object parameter)
    {
        // 从命令参数中获取TextEditor实例
        if (parameter is TextEditor textEditor)
        {
            // 获取之前已经安装好的SearchPanel实例
            var searchPanel = SearchPanel.GetSearchPanel(textEditor.TextArea);
            // 打开搜索面板,效果和按下Ctrl+F完全一致
            searchPanel.Open();
        }
    }

    // MVVM必备的INotifyPropertyChanged实现
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

第三步:修改XAML,绑定ViewModel和命令

把原来的代码隐藏式CommandBinding替换成ViewModel的命令绑定,同时把TextEditor作为命令参数传递给按钮,还要给窗口设置DataContext:

<Window x:Class="YourNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
        xmlns:local="clr-namespace:YourNamespace"
        Title="MainWindow" Height="450" Width="800">
    <!-- 将ViewModel设置为窗口的数据上下文 -->
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Left">
            <Button Name="FindButton" Content="Find" Margin="2" Style="{DynamicResource ButtonFooter_Style}"
                    <!-- 绑定ViewModel中的FindCommand -->
                    Command="{Binding FindCommand}"
                    <!-- 把TextEditor实例作为命令参数传递 -->
                    CommandParameter="{Binding ElementName=textEditor}">
            </Button>
            <avalonEdit:TextEditor Grid.Row="2" Grid.Column="1" Name="textEditor" FontFamily="Consolas" FontSize="10pt" SyntaxHighlighting="XML" ShowLineNumbers="True" >
            </avalonEdit:TextEditor>
        </StackPanel>
    </Grid>
</Window>

第四步:确认TextEditor的SearchPanel已正确安装

你原来的TextEditor构造函数已经完成了这一步,完全没问题,再确认下:

public TextEditor() : this(new TextArea())
{
    Search.SearchPanel.Install(this.TextArea);
}

补充说明

  • 我们通过SearchPanel.GetSearchPanel(textEditor.TextArea)获取之前安装好的搜索面板实例,而不是重新创建,这样能保证和Ctrl+F触发的是同一个面板,搜索状态也会同步。
  • 如果你的项目已经有了类似RelayCommand的实现(比如Prism的DelegateCommand),可以直接用自己的,不用重复编写。

内容的提问来源于stack exchange,提问作者user1910087

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:22:10