I'm building an application using CefSharp and need to provide text search functionality to user just like Google Chrome has.
Can any one help me with the implementation of text search in CefSharp?
I'm building an application using CefSharp and need to provide text search functionality to user just like Google Chrome has.
Can any one help me with the implementation of text search in CefSharp?
I've built this demo application using CefSharp 47.0.3, hopefully this is what you're looking for.
The view:
<Window x:Class="CefSharpSearchDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpf="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cefSharpSearchDemo="clr-namespace:CefSharpSearchDemo"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
d:DataContext="{d:DesignInstance {x:Type cefSharpSearchDemo:MainWindowViewModel}}">
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<Button Content="Next" DockPanel.Dock="Right" Command="{Binding ElementName=SearchBehavior, Path=NextCommand}" />
<Button Content="Previous" DockPanel.Dock="Right" Command="{Binding ElementName=SearchBehavior, Path=PreviousCommand}" />
<TextBox DockPanel.Dock="Right" Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</DockPanel>
<wpf:ChromiumWebBrowser x:Name="wb" DockPanel.Dock="Bottom"
Address="http://stackoverflow.com">
<i:Interaction.Behaviors>
<cefSharpSearchDemo:ChromiumWebBrowserSearchBehavior x:Name="SearchBehavior" SearchText="{Binding SearchText}" />
</i:Interaction.Behaviors>
</wpf:ChromiumWebBrowser>
</DockPanel>
</Window>
The code-behind for the view:
namespace CefSharpSearchDemo
{
using System.Windows;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
}
The view model:
namespace CefSharpSearchDemo
{
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _searchText;
public string SearchText
{
get { return _searchText; }
set
{
_searchText = value;
NotifyPropertyChanged();
}
}
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And now the important part. As you could see in the view there is a behavior attached to the ChromiumWebBrowser
:
namespace CefSharpSearchDemo
{
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using CefSharp;
using CefSharp.Wpf;
public class ChromiumWebBrowserSearchBehavior : Behavior<ChromiumWebBrowser>
{
private bool _isSearchEnabled;
public ChromiumWebBrowserSearchBehavior()
{
NextCommand = new DelegateCommand(OnNext);
PreviousCommand = new DelegateCommand(OnPrevious);
}
private void OnNext()
{
AssociatedObject.Find(identifier: 1, searchText: SearchText, forward: true, matchCase: false, findNext: true);
}
private void OnPrevious()
{
AssociatedObject.Find(identifier: 1, searchText: SearchText, forward: false, matchCase: false, findNext: true);
}
protected override void OnAttached()
{
AssociatedObject.FrameLoadEnd += ChromiumWebBrowserOnFrameLoadEnd;
}
private void ChromiumWebBrowserOnFrameLoadEnd(object sender, FrameLoadEndEventArgs frameLoadEndEventArgs)
{
_isSearchEnabled = frameLoadEndEventArgs.Frame.IsMain;
Dispatcher.Invoke(() =>
{
if (_isSearchEnabled && !string.IsNullOrEmpty(SearchText))
{
AssociatedObject.Find(1, SearchText, true, false, false);
}
});
}
public static readonly DependencyProperty SearchTextProperty = DependencyProperty.Register(
"SearchText", typeof(string), typeof(ChromiumWebBrowserSearchBehavior), new PropertyMetadata(default(string), OnSearchTextChanged));
public string SearchText
{
get { return (string)GetValue(SearchTextProperty); }
set { SetValue(SearchTextProperty, value); }
}
public static readonly DependencyProperty NextCommandProperty = DependencyProperty.Register(
"NextCommand", typeof (ICommand), typeof (ChromiumWebBrowserSearchBehavior), new PropertyMetadata(default(ICommand)));
public ICommand NextCommand
{
get { return (ICommand) GetValue(NextCommandProperty); }
set { SetValue(NextCommandProperty, value); }
}
public static readonly DependencyProperty PreviousCommandProperty = DependencyProperty.Register(
"PreviousCommand", typeof (ICommand), typeof (ChromiumWebBrowserSearchBehavior), new PropertyMetadata(default(ICommand)));
public ICommand PreviousCommand
{
get { return (ICommand) GetValue(PreviousCommandProperty); }
set { SetValue(PreviousCommandProperty, value); }
}
private static void OnSearchTextChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var behavior = dependencyObject as ChromiumWebBrowserSearchBehavior;
if (behavior != null && behavior._isSearchEnabled)
{
var newSearchText = dependencyPropertyChangedEventArgs.NewValue as string;
if (string.IsNullOrEmpty(newSearchText))
{
behavior.AssociatedObject.StopFinding(true);
}
else
{
behavior.AssociatedObject.Find(1, newSearchText, true, false, false);
}
}
}
protected override void OnDetaching()
{
AssociatedObject.FrameLoadEnd -= ChromiumWebBrowserOnFrameLoadEnd;
}
}
}
And the minor additional code for the DelegateCommand
:
namespace CefSharpSearchDemo
{
using System;
using System.Windows.Input;
public class DelegateCommand : ICommand
{
private readonly Action _action;
public DelegateCommand(Action action)
{
_action = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_action();
}
public event EventHandler CanExecuteChanged;
}
}
The resulting application has a TextBox
on the top and two buttons labeled "Previous" and "Next" next to it.
The main area is a CefSharp browser which loads http://www.stackoverflow.com.
You can type into the TextBox
and it will search in the browser (and highlight the scrollbar where the hits are, just like in Chrome). You can then press the Next/Previous buttons to cycle through the hits.
I hope this helps in developing your own solution.
All this said, let me just note that next time if you ask a question, actually provide some code what you tried, or try to ask a more specific question, because this is probably too broad for this site. Anyway I leave this here, maybe others will find it useful as well.
Important lesson: there are some methods exposed on ChromiumWebBrowser
that you can use to implement the search functionality (namely: Find
and StopFinding
).
You can do it simple just add two buttons
and a textbox
on your form.
first buttons
for next result,second buttons
for previous result and textbox
for search text provider.
if (tosBrowserSearchTxt.Text.Length <= 0)
{
//this will clear all search result
webBrowserChromium.StopFinding(true);
}
else
{
webBrowserChromium.Find(0, tosBrowserSearchTxt.Text, true, false,false);
}
webBrowserChromium.Find(0, tosBrowserSearchTxt.Text, true, false, false);
webBrowserChromium.Find(0, tosBrowserSearchTxt.Text, false, false, false);
When user type any character into text box KeyUp event's code will search that text, by using next and previous button you can navigate from one result to another.
I've built this demo application using CefSharp 47.0.3, hopefully this is what you're looking for.
The view:
<Window x:Class="CefSharpSearchDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpf="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cefSharpSearchDemo="clr-namespace:CefSharpSearchDemo"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
d:DataContext="{d:DesignInstance {x:Type cefSharpSearchDemo:MainWindowViewModel}}">
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<Button Content="Next" DockPanel.Dock="Right" Command="{Binding ElementName=SearchBehavior, Path=NextCommand}" />
<Button Content="Previous" DockPanel.Dock="Right" Command="{Binding ElementName=SearchBehavior, Path=PreviousCommand}" />
<TextBox DockPanel.Dock="Right" Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</DockPanel>
<wpf:ChromiumWebBrowser x:Name="wb" DockPanel.Dock="Bottom"
Address="http://stackoverflow.com">
<i:Interaction.Behaviors>
<cefSharpSearchDemo:ChromiumWebBrowserSearchBehavior x:Name="SearchBehavior" SearchText="{Binding SearchText}" />
</i:Interaction.Behaviors>
</wpf:ChromiumWebBrowser>
</DockPanel>
</Window>
The code-behind for the view:
namespace CefSharpSearchDemo
{
using System.Windows;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
}
The view model:
namespace CefSharpSearchDemo
{
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _searchText;
public string SearchText
{
get { return _searchText; }
set
{
_searchText = value;
NotifyPropertyChanged();
}
}
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And now the important part. As you could see in the view there is a behavior attached to the ChromiumWebBrowser
:
namespace CefSharpSearchDemo
{
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using CefSharp;
using CefSharp.Wpf;
public class ChromiumWebBrowserSearchBehavior : Behavior<ChromiumWebBrowser>
{
private bool _isSearchEnabled;
public ChromiumWebBrowserSearchBehavior()
{
NextCommand = new DelegateCommand(OnNext);
PreviousCommand = new DelegateCommand(OnPrevious);
}
private void OnNext()
{
AssociatedObject.Find(identifier: 1, searchText: SearchText, forward: true, matchCase: false, findNext: true);
}
private void OnPrevious()
{
AssociatedObject.Find(identifier: 1, searchText: SearchText, forward: false, matchCase: false, findNext: true);
}
protected override void OnAttached()
{
AssociatedObject.FrameLoadEnd += ChromiumWebBrowserOnFrameLoadEnd;
}
private void ChromiumWebBrowserOnFrameLoadEnd(object sender, FrameLoadEndEventArgs frameLoadEndEventArgs)
{
_isSearchEnabled = frameLoadEndEventArgs.Frame.IsMain;
Dispatcher.Invoke(() =>
{
if (_isSearchEnabled && !string.IsNullOrEmpty(SearchText))
{
AssociatedObject.Find(1, SearchText, true, false, false);
}
});
}
public static readonly DependencyProperty SearchTextProperty = DependencyProperty.Register(
"SearchText", typeof(string), typeof(ChromiumWebBrowserSearchBehavior), new PropertyMetadata(default(string), OnSearchTextChanged));
public string SearchText
{
get { return (string)GetValue(SearchTextProperty); }
set { SetValue(SearchTextProperty, value); }
}
public static readonly DependencyProperty NextCommandProperty = DependencyProperty.Register(
"NextCommand", typeof (ICommand), typeof (ChromiumWebBrowserSearchBehavior), new PropertyMetadata(default(ICommand)));
public ICommand NextCommand
{
get { return (ICommand) GetValue(NextCommandProperty); }
set { SetValue(NextCommandProperty, value); }
}
public static readonly DependencyProperty PreviousCommandProperty = DependencyProperty.Register(
"PreviousCommand", typeof (ICommand), typeof (ChromiumWebBrowserSearchBehavior), new PropertyMetadata(default(ICommand)));
public ICommand PreviousCommand
{
get { return (ICommand) GetValue(PreviousCommandProperty); }
set { SetValue(PreviousCommandProperty, value); }
}
private static void OnSearchTextChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var behavior = dependencyObject as ChromiumWebBrowserSearchBehavior;
if (behavior != null && behavior._isSearchEnabled)
{
var newSearchText = dependencyPropertyChangedEventArgs.NewValue as string;
if (string.IsNullOrEmpty(newSearchText))
{
behavior.AssociatedObject.StopFinding(true);
}
else
{
behavior.AssociatedObject.Find(1, newSearchText, true, false, false);
}
}
}
protected override void OnDetaching()
{
AssociatedObject.FrameLoadEnd -= ChromiumWebBrowserOnFrameLoadEnd;
}
}
}
And the minor additional code for the DelegateCommand
:
namespace CefSharpSearchDemo
{
using System;
using System.Windows.Input;
public class DelegateCommand : ICommand
{
private readonly Action _action;
public DelegateCommand(Action action)
{
_action = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_action();
}
public event EventHandler CanExecuteChanged;
}
}
The resulting application has a TextBox
on the top and two buttons labeled "Previous" and "Next" next to it.
The main area is a CefSharp browser which loads http://www.stackoverflow.com.
You can type into the TextBox
and it will search in the browser (and highlight the scrollbar where the hits are, just like in Chrome). You can then press the Next/Previous buttons to cycle through the hits.
I hope this helps in developing your own solution.
All this said, let me just note that next time if you ask a question, actually provide some code what you tried, or try to ask a more specific question, because this is probably too broad for this site. Anyway I leave this here, maybe others will find it useful as well.
Important lesson: there are some methods exposed on ChromiumWebBrowser
that you can use to implement the search functionality (namely: Find
and StopFinding
).
© 2022 - 2024 — McMap. All rights reserved.