User control with WebBrowser in C# - c#

I'm writing user control with WebBrowser and one dependency property.
After change in Text I'd like to refresh browser output.
public class BrowserControl : Control
{
//....
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register("Text", typeof(object), typeof(BrowserControl), new UIPropertyMetadata(null));
public String Text
{
get { return (String)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value);
br = new WebBrowser();
br.NavigateToString(value);
}
}
private WebBrowser br;
public WebBrowser Browser { get; set; }
}
I have put this control in wpf application, but there is no output from control. I think that I have to modify control template.
General template looks like:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BrowserControl">
<Style TargetType="{x:Type local:BrowserControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:BrowserControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
I am new to this and don't know how to put webbrowser as visible element of entire control?
Also I'd like to know how to use Binding with TextBox and BrowserControl's Text property in WPF application.
I want to do sth like:
<TextBox ... Text="{Binding Path=browserCtrl.Text}" ...>
So when text in TextBox change my custom control will rerender the site in browser.

I think this might help you....
just type the URL and tab off.
BrowserControl.cs
public class BrowserControl : Control
{
public static readonly DependencyProperty URLproperty
= DependencyProperty.Register(
"URL",
typeof (string),
typeof (BrowserControl),
new PropertyMetadata(string.Empty, OnURLPropertyChanged),
OnValidateURLCallBack);
private static bool OnValidateURLCallBack(object value)
{
Uri uri = null;
var url = Convert.ToString(value);
if (!string.IsNullOrEmpty(url))
{
return Uri.TryCreate(Convert.ToString(value), UriKind.Absolute, out uri);
}
return true;
}
private static void OnURLPropertyChanged(object sender, DependencyPropertyChangedEventArgs args)
{
var browserControl = sender as BrowserControl;
if (browserControl != null)
{
Uri uri = null;
var url = Convert.ToString(args.NewValue);
var template = browserControl.Template;
if (template != null)
{
var internalBrowser =
browserControl.Template.FindName("_InternalBrowser", browserControl) as WebBrowser;
if (internalBrowser != null)
{
if (!string.IsNullOrEmpty(url) && Uri.TryCreate(url, UriKind.Absolute, out uri))
{
internalBrowser.Navigate(uri);
}
else if (string.IsNullOrEmpty(url))
{
internalBrowser.NavigateToStream(new MemoryStream(Encoding.ASCII.GetBytes(string.Empty)));
}
}
}
}
}
public string URL
{
get { return Convert.ToString(GetValue(URLproperty)); }
set { SetValue(URLproperty, value); }
}
}
Generic.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1">
<Style TargetType="{x:Type local:BrowserControl}" x:Key="{x:Type local:BrowserControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:BrowserControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<WebBrowser x:Name="_InternalBrowser"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="BrowserHost" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel Margin="2">
<TextBlock FontWeight="Bold" Text="URL: " Margin="1" DockPanel.Dock="Left"/>
<TextBox Text="{Binding ElementName=MyBrowserControl, Path=URL, Mode=TwoWay}" DockPanel.Dock="Right"/>
</DockPanel>
<local:BrowserControl x:Name="MyBrowserControl" Grid.Row="1" BorderBrush="Blue" BorderThickness="1">
</local:BrowserControl>
</Grid>
</Window>

You might find it easier to use the UserControl class... just add a WebBrowser control into the UserControl XAML and then add your DependencyProperty into the code behind:
<UserControl x:Class="WpfApplication1.Views.WebBrowserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<WebBrowser Name="WebBrowser" /><!--Declare this here, not in code behind-->
</UserControl>
For your second requirement, you should investigate the WebBrowser.WebBrowser.Navigate and/or the WebBrowser.NavigateToString methods.
Finally, to react to changes in the DependencyProperty, you'll need to add a PropertyChangedCallback handler. You can find out how to do this by looking at the Dependency Property Callbacks and Validation page on MSDN.

Related

WPF Custom Control based on grid or nested grid?

I'm learning WPF but I have a lot of Windows Forms background. I want to convert a WinForms custom control in which I did put a label and a textbox (making a TextField), with a property allowing to set percentage of width allocated to the label.
Now, in WPF, I'm a bit lost. Should I create a custom control that inherits from a grid and expose (how ?) the columns definition properties, or should I create a custom control that will "contain" a grid, and expose two properties "LabelWidth" and "ContentWidth", and bind the two column definitions to these properties ? (Thinking these properties would contain 1* and 3*).
Could someone show me an example of such construction to have a place to start?
You could create a UserControl with two dependency properties.
Please refer to the following sample code.
MyUserControl.xaml:
<UserControl x:Class="WpfApplication3.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication3"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding LabelWidth, RelativeSource={RelativeSource AncestorType=UserControl}}" />
<ColumnDefinition Width="{Binding ContentWidth, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</Grid.ColumnDefinitions>
<TextBlock Text="..." />
<TextBox Grid.Column="1" />
</Grid>
</UserControl>
MyUserControl.xaml.cs:
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public static readonly DependencyProperty LabelWidthProperty =
DependencyProperty.Register("LabelWidth", typeof(System.Windows.GridLength),
typeof(MyUserControl));
public System.Windows.GridLength LabelWidth
{
get { return (System.Windows.GridLength)GetValue(LabelWidthProperty); }
set { SetValue(LabelWidthProperty, value); }
}
public static readonly DependencyProperty ContentWidthProperty =
DependencyProperty.Register("ContentWidth", typeof(System.Windows.GridLength),
typeof(MyUserControl));
public System.Windows.GridLength ContentWidth
{
get { return (System.Windows.GridLength)GetValue(ContentWidthProperty); }
set { SetValue(ContentWidthProperty, value); }
}
}
Sample usage:
<local:MyUserControl LabelWidth="1*" ContentWidth="5*" />
Dependency Properties Overview: https://msdn.microsoft.com/en-us/library/ms752914(v=vs.110).aspx
I think I managed to achieve what I wanted to do by understanding mm8's code, in particular RelativeSource={RelativeSource AncestorType=UserControl} :
Added a custom control.
FieldText.cs :
public class FieldText : Control
{
static FieldText()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FieldText), new FrameworkPropertyMetadata(typeof(FieldText)));
}
public FieldText()
{
}
public static readonly DependencyProperty LabelLengthProperty =
DependencyProperty.Register("LabelLength", typeof(GridLength),
typeof(FieldText), new UIPropertyMetadata(new GridLength(25, GridUnitType.Star)));
public virtual GridLength LabelLength
{
get { return (GridLength)GetValue(LabelLengthProperty); }
set { SetValue(LabelLengthProperty, value); }
}
public static readonly DependencyProperty ContentLengthProperty =
DependencyProperty.Register("ContentLength", typeof(GridLength),
typeof(FieldText), new UIPropertyMetadata(new GridLength(75, GridUnitType.Star)));
public virtual GridLength ContentLength
{
get { return (GridLength)GetValue(ContentLengthProperty); }
set { SetValue(ContentLengthProperty, value); }
}
}
Generic.xaml :
<Style TargetType="{x:Type controls:FieldText}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:FieldText}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid x:Name="grd" Margin="3px">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Path=LabelLength, RelativeSource={RelativeSource AncestorType=Control}}" />
<ColumnDefinition Width="{Binding Path=ContentLength, RelativeSource={RelativeSource AncestorType=Control}}" />
</Grid.ColumnDefinitions>
<Label x:Name="label" Grid.Column="0" Content="Field:" />
<TextBox x:Name="textbox" Grid.Column="1" MaxLines="1" TextWrapping="NoWrap" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Sample usage:
<controls:FieldText x:Name="fld1" LabelLength="25*" ContentLength="75*" />

WPF XAML Binding Not Picking Up DependencyProperty Value

I have a really simple UserControl
<UserControl x:Class="Namespace.Views.TabViews.TabViewTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="900" d:DesignWidth="880"
d:DataContext="{d:DesignData Type=TabViewTemplate}">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderBrush="#FFB31B16" BorderThickness="0,0,0,1" Margin="20" VerticalAlignment="Top">
<TextBlock VerticalAlignment="Bottom" FontSize="20" LineHeight="24" Margin="0,0,0,5" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Title}"/>
</Border>
<Border Grid.Row="1" Padding="20">
<ContentPresenter ContentSource="Content"/>
</Border>
</Grid>
</ControlTemplate>
</UserControl.Template>
</UserControl>
and it's code behind
using System;
using System.Windows;
using System.Windows.Markup;
namespace Namespace.Views.TabViews {
/// <summary>
/// Interaction logic for TabViewTemplate.xaml
/// </summary>
[ContentProperty("Content")]
public partial class TabViewTemplate {
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(TabViewTemplate),
new FrameworkPropertyMetadata(
"Sample",
FrameworkPropertyMetadataOptions.AffectsRender,
OnTitleChanged)
);
private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var control = d as TabViewTemplate;
if (control != null) control.Title = (string)e.NewValue;
}
public TabViewTemplate() {
InitializeComponent();
}
public static void SetTitle(TabViewTemplate element, string value) {
element.SetValue(TitleProperty, value);
}
public static string GetTitle(TabViewTemplate element) {
return (string) element.GetValue(TitleProperty);
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
}
}
I make use of that code like this
<UserControl x:Class="Namespace.Views.TabViews.WelcomeTabView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
xmlns:tabViews="clr-namespace:Namespace.Views.TabViews"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<tabViews:TabViewTemplate Title="Welcome">
<Grid>
<Border BorderBrush="Coral" BorderThickness="2" Margin="0">
<Image gif:ImageBehavior.AnimatedSource="../../Resources/js_cfg_install_howto.gif"/>
</Border>
</Grid>
</tabViews:TabViewTemplate>
</UserControl>
However the value "Welcome" gets set via the property -- I see this via a breakpoint on the property setter -- however the get is never called. I have used all sorts of Binding combinations, none of which work. What is the "correct" way to set the TextBlock Text by way of a DependencyProperty? Thanks!
It was working. My TextBlock needed a Foreground of Black in order to see the text.

WPF CustomControl stops showing up 50% of the time

I have a custom control in my WPF project, I've defined the style, the class, and I've called it in my xaml and made sure to include a reference. when I start the project 50% of the time the custom object renders perfectly, the other 50% it just doesn't show up, but is still interactable.
public class PermissionBox : Control
{
public PermissionBox()
{
DefaultStyleKey = typeof(PermissionBox);
}
public string PumpID
{
get
{
return (string)GetValue(PumpIDProperty);
}
set
{
SetValue(PumpIDProperty, value);
}
}
public static readonly DependencyProperty PumpIDProperty =
DependencyProperty.Register("PumpID", typeof(string), typeof(PermissionBox), new PropertyMetadata(string.Empty));
public string FuelType
{
get
{
return (string)GetValue(FuelTypeProperty);
}
set
{
SetValue(FuelTypeProperty, value);
}
}
public static readonly DependencyProperty FuelTypeProperty =
DependencyProperty.Register("FuelType", typeof(string), typeof(PermissionBox), new PropertyMetadata(string.Empty));
}
in Themes/Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:POS">
<Style TargetType="{x:Type controls:PermissionBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:PermissionBox}">
<Grid Background="Gray" Opacity="0.8">
<TextBlock Foreground="Black" FontSize="15" Text="Pump ID:" HorizontalAlignment="Left"/>
<TextBlock Foreground="Black" FontSize="15" Text="{TemplateBinding PumpID}" HorizontalAlignment="Right"/>
<TextBlock Foreground="Black" FontSize="15" Text="Fuel Type:" HorizontalAlignment="Left"/>
<TextBlock Foreground="Black" FontSize="15" Text="{TemplateBinding FuelType}" HorizontalAlignment="Right"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and the calling window
<Window x:Class="POS.Window1"
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:controls="clr-namespace:POS"
mc:Ignorable="d"
Title="Window1" Height="300" Width="300">
<Grid>
<controls:PermissionBox PumpID="100" FuelType="Unleaded"> </controls:PermissionBox>
</Grid>
</Window>
Really appreciate any help with resolving this.

Modify TextBox value when Button was clicked in custom control library

I create one textbox and button in custom control library, the initial text box value is "Welcome" when the button was clicked the textbox text value is modified to "Hi".
Generic.Xaml:
<ResourceDictionary
x:Class="WpfCustomControlLibrary2.Themes.Class1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCustomControlLibrary2">
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<WrapPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox x:Name="txb" Text="Welcome" Width="50" Height="30" FontSize="15"/>
<Button Content="+" Width="35" Height="30" FontSize="15" Click="Button_Click_Add" />
</WrapPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Class1.cs:
namespace WpfCustomControlLibrary2.Themes
{
partial class Class1
{
private void Button_Click_Add(object sender, RoutedEventArgs e)
{
//What i do here
}
}
}
MainWindow.Xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCustomControlLibrary2;assembly=WpfCustomControlLibrary2"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="grid">
<local:CustomControl1 />
</Grid>
</Window>
Please help to solve this problem, Thanks
You can`t do it, like you do it.
And you must follow name rules also.
Try it:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCustomControlLibrary2;assembly=WpfCustomControlLibrary2">
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<WrapPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox x:Name="PART_TextBox" Text="Welcome"/>
<Button x:Name="PART_Button" Content="+" />
</WrapPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
and
[TemplatePart(Name = "PART_TextBox", Type = typeof(TextBox))]
[TemplatePart(Name = "PART_Button", Type = typeof(Button))]
public class CustomControl1 : Control
{
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
public CustomControl1()
{
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var button = GetTemplateChild("PART_Button") as Button;
if (button != null)
{
button.Click += Button_Click;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var textBox = GetTemplateChild("PART_TextBox") as TextBox;
if (textBox != null)
{
textBox.Text = "HI!";
}
}
}

Windows Phone - Binding solidcolorbrush property using dependendy property

I have a custom control named Tile where containing a border.
I want to be able to change the Tile's border backcolor in my MainPage.xaml where I'm adding the control:
Here is the code of my tile class:
public static readonly DependencyProperty MyDpProperty = DependencyProperty.Register
("TileColor",
typeof(SolidColorBrush),
typeof(Tile),
new PropertyMetadata(default(SolidColorBrush)));
public SolidColorBrush TileColor
{
get
{
return (SolidColorBrush)this.GetValue(MyDpProperty);
}
set
{
this.SetValue(MyDpProperty, value);
}
}
Here is the xaml from my Tile CustomControl:
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<Border Background="{Binding TileColor}"></Border>
</Grid>
And here is my MainPage.xaml:
<local:Tile Grid.Column="5">
<local:Tile.TileColor>
<SolidColorBrush Color="Beige"></SolidColorBrush>
</local:Tile.TileColor>
</local:Tile>
The tile appears, but the color won't set..
Could you please point me where I'm wrong ?
You need to rename the DependencyProperty to TileColorProperty (as #dkozl says) and you also need to use {TemplateBinding} in the control:
Themes\generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:local="clr-namespace:Silverlight80App">
<Style TargetType="local:Tile">
<Setter Property="TileColor" Value="Aquamarine"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Tile">
<Rectangle Fill="{TemplateBinding TileColor}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Tile.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Silverlight80App
{
class Tile : ContentControl
{
public static readonly DependencyProperty TileColorProperty =
DependencyProperty.Register("TileColor", typeof(Brush), typeof(Tile),
null);
public Brush TileColor
{
get { return (Brush)GetValue(TileColorProperty); }
set { SetValue(TileColorProperty, value); }
}
public Tile()
{
DefaultStyleKey = typeof(Tile);
}
}
}
Usage
<StackPanel xmlns:local="clr-namespace:Silverlight80App">
<local:Tile HorizontalAlignment="Stretch" Height="10" />
<local:Tile HorizontalAlignment="Stretch" Height="10" TileColor="Red"/>
</StackPanel>

Categories