diff --git a/CefSharp.MinimalExample.Wpf/Binding/Behaviors/HtmlBindingHelper.cs b/CefSharp.MinimalExample.Wpf/Binding/Behaviors/HtmlBindingHelper.cs new file mode 100644 index 00000000..f3b97ef2 --- /dev/null +++ b/CefSharp.MinimalExample.Wpf/Binding/Behaviors/HtmlBindingHelper.cs @@ -0,0 +1,38 @@ +using CefSharp.Wpf; +using System.Windows; + +namespace CefSharp.MinimalExample.Wpf.Binding.Behaviors +{ + public static class HtmlBindingHelper + { + // Using a DependencyProperty as the backing store for Html. This enables animation, styling, binding, etc... + public static readonly DependencyProperty HtmlProperty = + DependencyProperty.RegisterAttached( + "Html", + typeof(string), + typeof(HtmlBindingHelper), + new PropertyMetadata(string.Empty, OnHtmlChanged)); + + public static string GetHtml(DependencyObject obj) + { + return (string)obj.GetValue(HtmlProperty); + } + + public static void SetHtml(DependencyObject obj, string value) + { + obj.SetValue(HtmlProperty, value); + } + + private static void OnHtmlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + string htmlText = e.NewValue as string; + + if (string.IsNullOrWhiteSpace(htmlText)) + { + htmlText = string.Empty; + } + + ((ChromiumWebBrowser)d).LoadHtml(htmlText, "http://cefsharp/loadHtml"); + } + } +} diff --git a/CefSharp.MinimalExample.Wpf/Binding/BindableBase.cs b/CefSharp.MinimalExample.Wpf/Binding/BindableBase.cs new file mode 100644 index 00000000..0e03dd33 --- /dev/null +++ b/CefSharp.MinimalExample.Wpf/Binding/BindableBase.cs @@ -0,0 +1,24 @@ +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace CefSharp.MinimalExample.Wpf.Binding +{ + public class BindableBase : INotifyPropertyChanged + { + protected virtual void SetProperty<T>(ref T member, T val, + [CallerMemberName] string propertyName = null) + { + if (object.Equals(member, val)) { return; } + + member = val; + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + + public event PropertyChangedEventHandler PropertyChanged = delegate { }; + } +} diff --git a/CefSharp.MinimalExample.Wpf/Binding/RelayCommand.cs b/CefSharp.MinimalExample.Wpf/Binding/RelayCommand.cs new file mode 100644 index 00000000..92a45bc1 --- /dev/null +++ b/CefSharp.MinimalExample.Wpf/Binding/RelayCommand.cs @@ -0,0 +1,98 @@ +using System; +using System.Windows.Input; + +namespace CefSharp.MinimalExample.Wpf.Binding +{ + public class RelayCommand : ICommand + { + Action _TargetExecuteMethod; + Func<bool> _TargetCanExecuteMethod; + + public RelayCommand(Action executeMethod) + { + _TargetExecuteMethod = executeMethod; + } + + public RelayCommand(Action executeMethod, Func<bool> canExecuteMethod) + { + _TargetExecuteMethod = executeMethod; + _TargetCanExecuteMethod = canExecuteMethod; + } + + public void RaiseCanExecuteChanged() + { + CanExecuteChanged(this, EventArgs.Empty); + } + #region ICommand Members + + bool ICommand.CanExecute(object parameter) + { + if (_TargetCanExecuteMethod != null) + { + return _TargetCanExecuteMethod(); + } + if (_TargetExecuteMethod != null) + { + return true; + } + return false; + } + + // Beware - should use weak references if command instance lifetime is longer than lifetime of UI objects that get hooked up to command + // Prism commands solve this in their implementation + public event EventHandler CanExecuteChanged = delegate { }; + + void ICommand.Execute(object parameter) + { + _TargetExecuteMethod?.Invoke(); + } + #endregion + } + + public class RelayCommand<T> : ICommand + { + Action<T> _TargetExecuteMethod; + Func<T, bool> _TargetCanExecuteMethod; + + public RelayCommand(Action<T> executeMethod) + { + _TargetExecuteMethod = executeMethod; + } + + public RelayCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod) + { + _TargetExecuteMethod = executeMethod; + _TargetCanExecuteMethod = canExecuteMethod; + } + + public void RaiseCanExecuteChanged() + { + CanExecuteChanged(this, EventArgs.Empty); + } + #region ICommand Members + + bool ICommand.CanExecute(object parameter) + { + if (_TargetCanExecuteMethod != null) + { + T tparm = (T)parameter; + return _TargetCanExecuteMethod(tparm); + } + if (_TargetExecuteMethod != null) + { + return true; + } + return false; + } + + // Beware - should use weak references if command instance lifetime is longer than lifetime of UI objects that get hooked up to command + // Prism commands solve this in their implementation + public event EventHandler CanExecuteChanged = delegate { }; + + void ICommand.Execute(object parameter) + { + _TargetExecuteMethod?.Invoke((T)parameter); + } + #endregion + } +} diff --git a/CefSharp.MinimalExample.Wpf/CefSharp.MinimalExample.Wpf.csproj b/CefSharp.MinimalExample.Wpf/CefSharp.MinimalExample.Wpf.csproj index 966eb5c8..c78243fc 100644 --- a/CefSharp.MinimalExample.Wpf/CefSharp.MinimalExample.Wpf.csproj +++ b/CefSharp.MinimalExample.Wpf/CefSharp.MinimalExample.Wpf.csproj @@ -86,6 +86,8 @@ <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </ApplicationDefinition> + <Compile Include="Binding\Behaviors\HtmlBindingHelper.cs" /> + <Compile Include="Binding\RelayCommand.cs" /> <Page Include="MainWindow.xaml"> <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> @@ -94,7 +96,9 @@ <DependentUpon>App.xaml</DependentUpon> <SubType>Code</SubType> </Compile> + <Compile Include="Binding\BindableBase.cs" /> <Compile Include="Binding\TitleConverter.cs" /> + <Compile Include="MainViewModel.cs" /> <Compile Include="MainWindow.xaml.cs"> <DependentUpon>MainWindow.xaml</DependentUpon> <SubType>Code</SubType> diff --git a/CefSharp.MinimalExample.Wpf/MainViewModel.cs b/CefSharp.MinimalExample.Wpf/MainViewModel.cs new file mode 100644 index 00000000..ff3da854 --- /dev/null +++ b/CefSharp.MinimalExample.Wpf/MainViewModel.cs @@ -0,0 +1,37 @@ +using CefSharp.MinimalExample.Wpf.Binding; +using System.Windows.Input; + +namespace CefSharp.MinimalExample.Wpf +{ + public class MainViewModel : BindableBase + { + private string html; + + public MainViewModel() + { + ViewHtmlCommand = new RelayCommand(OnViewHtml); + Address = "www.google.com"; + } + + public string Html + { + get { return html; } + set { SetProperty(ref html, value); } + } + + private string address; + + public string Address + { + get { return address; } + set { SetProperty(ref address, value); } + } + + public ICommand ViewHtmlCommand { get; private set; } + + private void OnViewHtml() + { + Html = "<div dir=\"ltr\"><b><i>test</i></b></div>\r\n"; + } + } +} diff --git a/CefSharp.MinimalExample.Wpf/MainWindow.xaml b/CefSharp.MinimalExample.Wpf/MainWindow.xaml index 70ad9e34..4e186549 100644 --- a/CefSharp.MinimalExample.Wpf/MainWindow.xaml +++ b/CefSharp.MinimalExample.Wpf/MainWindow.xaml @@ -2,6 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:wpf="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf" + xmlns:behaviors="clr-namespace:CefSharp.MinimalExample.Wpf.Binding.Behaviors" Title="{Binding Path=Title, ElementName=Browser, Converter={StaticResource TitleConverter}}" WindowState="Maximized"> <Grid> @@ -11,16 +12,45 @@ </Grid.RowDefinitions> <wpf:ChromiumWebBrowser Grid.Row="0" x:Name="Browser" - Address="http://www.google.com" /> + Address="{Binding Address}" + behaviors:HtmlBindingHelper.Html="{Binding Html}"/> + <StatusBar Grid.Row="1"> - <ProgressBar HorizontalAlignment="Right" - IsIndeterminate="{Binding IsLoading, ElementName=Browser}" - Width="100" - Height="16" - Margin="3" /> - <Separator /> - <!-- TODO: Could show hover link URL here --> - <TextBlock Text="{Binding Address, ElementName=Browser}"/> + <StatusBar.ItemsPanel> + <ItemsPanelTemplate> + <Grid > + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="2*" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + </Grid> + </ItemsPanelTemplate> + </StatusBar.ItemsPanel> + <StatusBarItem> + <Button Content="View HTML" Command="{Binding ViewHtmlCommand}" Padding="3,0"/> + </StatusBarItem> + <Separator Grid.Column="1"/> + <StatusBarItem Grid.Column="2"> + <ProgressBar HorizontalAlignment="Right" + IsIndeterminate="{Binding IsLoading, ElementName=Browser}" + Width="100" + Height="16" + Margin="3" /> + </StatusBarItem> + <Separator Grid.Column="3"/> + <StatusBarItem Grid.Column="4"> + <!-- TODO: Could show hover link URL here --> + <TextBlock Text="{Binding Address, ElementName=Browser}" /> + </StatusBarItem> + <Separator Grid.Column="5"/> + <StatusBarItem Grid.Column="6" HorizontalContentAlignment="Stretch"> + <TextBox Text="{Binding Address, UpdateSourceTrigger=PropertyChanged}" /> + </StatusBarItem> </StatusBar> </Grid> </Window> diff --git a/CefSharp.MinimalExample.Wpf/MainWindow.xaml.cs b/CefSharp.MinimalExample.Wpf/MainWindow.xaml.cs index bc19c9cf..ac416b1a 100644 --- a/CefSharp.MinimalExample.Wpf/MainWindow.xaml.cs +++ b/CefSharp.MinimalExample.Wpf/MainWindow.xaml.cs @@ -7,6 +7,7 @@ public partial class MainWindow : Window public MainWindow() { InitializeComponent(); + DataContext = new MainViewModel(); } } }