Modify TextBox value when Button was clicked in custom control library - c#

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!";
}
}
}

Related

Content is not showing

Unfortunately, I'm unable to understand where there is realization mistake.
The main application window should show a content from view model (HomeView.xaml)
Could you advice, what I has done incorrect?
Thanks in advance.
https://i.stack.imgur.com/mq3PS.png
MainWindow.xaml.cs
using ohb.MVVM.ViewModel;
namespace ohb
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new HomeViewModel();
}
// Moveable window
private void WindowMouseMoving(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
this.DragMove();
}
}
// Exit button
private void CloseButtonClick(object sender, RoutedEventArgs e)
{
Close();
}
}
}
MainWindow.xaml
<Window x:Class="ohb.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:local="clr-namespace:ohb"
xmlns:viewModel="clr-namespace:ohb.MVVM.ViewModel"
xmlns:view="clr-namespace:ohb.MVVM.View"
mc:Ignorable="d"
Height="600" Width="920"
WindowStyle="None"
ResizeMode="NoResize"
Background="Transparent"
AllowsTransparency="True"
MouseMove="WindowMouseMoving">
<Window.DataContext>
<viewModel:MainViewModel/>
</Window.DataContext>
<Border Background="#2f4f4f"
CornerRadius="30">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="75"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="Application"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Foreground="White"
FontSize="22"
Margin="20,0,0,0"/>
<StackPanel Grid.Row="1">
<RadioButton Content="Home"
Height="50"
Foreground="White"
FontSize="14"
Style="{StaticResource MenuButtonTheme}"
IsChecked="True"
Command="{Binding HomeViewCommand}"/>
<RadioButton Content="Menu"
Height="50"
Foreground="White"
FontSize="14"
Style="{StaticResource MenuButtonTheme}"
Command="{Binding DiscoveryViewCommand}"/>
<RadioButton Content="Settings"
Height="50"
Foreground="White"
FontSize="14"
Style="{StaticResource MenuButtonTheme}"/>
<RadioButton Content="Exit"
Click="CloseButtonClick"
Height="50"
Foreground="White"
FontSize="14"
Style="{StaticResource MenuButtonTheme}"/>
</StackPanel>
<TextBox Width="250"
Height="40"
VerticalContentAlignment="Center"
HorizontalAlignment="Left"
Margin="5"
Grid.Column="1"
Style="{StaticResource TextBoxTheme}"/>
<ContentControl Grid.Row="1"
Grid.Column="1"
Margin="10"
Content="{Binding CurrentView}"/>
</Grid>
</Border>
</Window>
App.xaml
<Application x:Class="ohb.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ohb"
xmlns:viewModel="clr-namespace:ohb.MVVM.ViewModel"
xmlns:view="clr-namespace:ohb.MVVM.View"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Theme/MenuButtonTheme.xaml"/>
<ResourceDictionary Source="Theme/TextBoxTheme.xaml"/>
</ResourceDictionary.MergedDictionaries>
<DataTemplate DataType="{x:Type viewModel:HomeViewModel}">
<view:HomeView/>
</DataTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
MenuButtonTheme.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style BasedOn="{StaticResource {x:Type ToggleButton}}"
TargetType="{x:Type RadioButton}"
x:Key="MenuButtonTheme">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<Grid VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Background="{TemplateBinding Background}">
<TextBlock Text="{TemplateBinding Property=Content}"
VerticalAlignment="Center"
Margin="50,0,0,0"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="#3b6363"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
TextBoxTheme.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type TextBox}"
x:Key="TextBoxTheme">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border CornerRadius="10"
Background="#3b6363"
Width="200" Height="40">
<Grid>
<Rectangle StrokeThickness="1"/>
<TextBox Margin="1"
BorderThickness="0"
Background="Transparent"
VerticalContentAlignment="Center"
Padding="5"
Foreground="White"
x:Name="SearchBox"/>
<TextBlock IsHitTestVisible="False"
Text="Search"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="10,0,0,0"
Foreground="DarkGray"
Grid.Column="1"
FontSize="12">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=SearchBox}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
<Setter Property="Visibility" Value="Hidden"/>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
ObservableObject.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace ohb.Core
{
class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
if (PropertyChanged != null)
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
}
RelayCommand.cs
using System.Windows.Input;
namespace ohb.Core
{
public class RelayCommand : ICommand
{
private Action<object> execute;
private 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)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
}
}
MainViewModel.cs
using System;
using ohb.Core;
namespace ohb.MVVM.ViewModel
{
class MainViewModel : ObservableObject
{
public RelayCommand HomeViewCommand { get; set; }
public HomeViewModel HomeVM { get; set; }
private object _currentView;
public object CurrentView
{
get { return _currentView; }
set
{
_currentView = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
HomeVM = new HomeViewModel();
CurrentView = HomeVM;
HomeViewCommand = new RelayCommand(o =>
{
CurrentView = HomeVM;
});
}
}
}
HomeViewModel.cs
using ohb.Core;
namespace ohb.MVVM.ViewModel
{
class HomeViewModel
{
}
}
HomeView.xaml
<UserControl x:Class="ohb.MVVM.View.HomeView"
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:viewModel="clr-namespace:ohb.MVVM.ViewModel"
xmlns:view="clr-namespace:ohb.MVVM.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.DataContext>
<viewModel:HomeViewModel/>
</UserControl.DataContext>
<StackPanel>
<TextBlock Text="Discover"
Foreground="White"
FontSize="28"
HorizontalAlignment="Left"
Margin="0,0,0,20"/>
<StackPanel Orientation="Horizontal"
Margin="0,0,0,10">
<Border Width="400"
Height="200">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,2">
<GradientStop Color="#5bc3ff" Offset="0"/>
<GradientStop Color="#3aa0ff" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Border.Clip>
<RectangleGeometry RadiusX="10"
RadiusY="10"
Rect="0,0,400,200"/>
</Border.Clip>
<Grid>
<StackPanel>
<TextBlock Text="World leader
in global"
Foreground="White"
FontSize="28"
Margin="20,10,10,0"/>
<TextBlock Text="Get started"
Foreground="White"
FontSize="18"
Margin="20,10,10,0"/>
</StackPanel>
</Grid>
</Border>
<Border Width="200"
Height="200"
CornerRadius="10"
Margin="45,0,0,0">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,2">
<GradientStop Color="#5bc3ff" Offset="0"/>
<GradientStop Color="#3aa0ff" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
</Border>
</StackPanel>
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="Margin" Value="15,0,0,0"/>
</Style>
</StackPanel.Resources>
<TextBlock Text="most watched"
Foreground="White"
FontSize="20"
HorizontalAlignment="Left"
Margin="0,0,0,10"/>
<StackPanel Orientation="Horizontal">
<Border Width="150"
Height="150"
Background="#844eff"
CornerRadius="10"
Margin="0"/>
<Border Width="150"
Height="150"
Background="Red"
CornerRadius="10"/>
<Border Width="150"
Height="150"
Background="Gray"
CornerRadius="10"/>
<Border Width="150"
Height="150"
Background="Green"
CornerRadius="10"/>
</StackPanel>
</StackPanel>
</StackPanel>
</UserControl>
A UserControl must not explictly set its own DataContext, as you have declared it in HomeView.xaml as
<UserControl.DataContext>
<viewModel:HomeViewModel/>
</UserControl.DataContext>
This assignment breaks the value inheritance of the DataContext property, which is essential to make the below DataTemplate work. Instead of getting the current data item as its DataContext, the control would always use the one that was explicitly set.
<DataTemplate DataType="{x:Type viewModel:HomeViewModel}">
<view:HomeView/>
</DataTemplate>
So simply remove the DataContext assignment from the UserControl's XAML.

WPF GetTemplateChild get Nullrefrence exception

Hi I'm building a control I need to access checkbox in the code behind But I get the null error
this is my control
<Style TargetType="TreeViewItem" x:Key="CheckTreeViewItem" >
<Setter Property="IsExpanded" Value="{Binding Path=IsExpanded,Mode=TwoWay}"/>
</Style>
<Style TargetType="local:CheckTreeView">
<Setter Property="ItemContainerStyle" Value="{StaticResource CheckTreeViewItem}"/>
<Setter Property="ItemTemplate">
<Setter.Value>
<HierarchicalDataTemplate DataType="{x:Type local:CheckTreeSource}" ItemsSource="{Binding Children}">
<CheckBox x:Name="PART_CheckBox" Margin="1" IsChecked="{Binding IsChecked}">
<TextBlock Text="{Binding Text}"/>
</CheckBox>
</HierarchicalDataTemplate>
</Setter.Value>
</Setter>
</Style>
And this is how I access control
[TemplatePart(Name = CheckBox_Key, Type = typeof(CheckBox))]
public partial class CheckTreeView : TreeView
{
private const string CheckBox_Key = "PART_CheckBox";
CheckBox checkBox;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
checkBox = GetTemplateChild(CheckBox_Key) as CheckBox;
checkBox.Click += CheckBox_Click;
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
}
}
When I use the following code I get no null error but no control in runtime
static CheckTreeView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CheckTreeView),
new FrameworkPropertyMetadata(typeof(CheckTreeView)));
}
To subscribe to Click event of each CheckBox:
public partial class CheckTreeView : TreeView
{
public CheckTreeView()
{
InitializeComponent();
processNode(this);
}
void processNode(ItemsControl node)
{
node.ItemContainerGenerator.StatusChanged += (sender, args) =>
{
ItemContainerGenerator itemContainerGenerator = ((ItemContainerGenerator)sender);
if (itemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
for (int i = 0; i < itemContainerGenerator.Items.Count; i++)
{
TreeViewItem treeViewItem =
(TreeViewItem) itemContainerGenerator.ContainerFromIndex(i);
treeViewItem.Loaded += (o, eventArgs) =>
{
CheckBox checkBox = FindVisualChild<CheckBox>(treeViewItem);
checkBox.Click += CheckBox_Click;
};
processNode(treeViewItem);
}
}
};
}
public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
if (obj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
var child = VisualTreeHelper.GetChild(obj, i);
if (child is T)
{
return (T)child;
}
T childItem = FindVisualChild<T>(child);
if (childItem != null) return childItem;
}
}
return null;
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
}
}
Note that if you use ObservableCollection as items source, you should process changes in that collection: subscribe to events of added items, unsubscribe from events of removed items.
CheckBox_Key element is not a part of CheckTreeView.ControlTemplate. It will be a part in tree view nodes, multiple times. GetTemplateChild won't find it
I would say that intead of CheckBox in ItemTemplate for CheckTreeView, you need to change TreeViewItem.Template and add CheckBox there. It won't help with GetTemplateChild, but is is more logical approach to build reusable TreeView with chechboxes.
Here is an example. Check/Uncheck operations can be handled by specail Command in CheckTreeView class:
public class CheckTreeView: TreeView
{
public CheckTreeView()
{
CheckCommand = new RelayCommand<object>(o => MessageBox.Show(o?.ToString()));
}
public ICommand CheckCommand
{
get { return (ICommand)GetValue(CheckCommandProperty); }
set { SetValue(CheckCommandProperty, value); }
}
public static readonly DependencyProperty CheckCommandProperty =
DependencyProperty.Register("CheckCommand", typeof(ICommand), typeof(CheckTreeView), new PropertyMetadata(null));
}
relevant part of TreeViewItem template (use Edit template feature in WPF designer to get full template):
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="19" Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<StackPanel Orientation="Horizontal">
<CheckBox Command="{Binding CheckCommand, RelativeSource={RelativeSource AncestorType={x:Type local:CheckTreeView}}}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}"
Margin="0,0,4,0"/>
<ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</StackPanel>
</Border>
<ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/>
</Grid>
</ControlTemplate/>
</Setter.Value>
</Setter>
</Style>

Binding custom Dependency Property on User Control with ControlTemplate

I've created a custom button with a ControlTemplate.
I used a ControlTemplate to make it possible to bind the default properties of UserControl, such as Background or Foreground.
But, if I add custom dependency properties (for example CornerRadius) I get two errors:
"The member 'CornerRadius' is not recognized or is not accessible."
"Cannot find the static member 'CornerRadiusProperty' on the type 'UserControl'."
Xaml:
<UserControl x:Class="MyProject.MyButton"
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="50" d:DesignWidth="50"
BorderThickness="1" BorderBrush="White" Background="Black"
Content="OK" Foreground="White">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Border Name="ground"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding CornerRadius}">
<Label Name="content"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Content="{TemplateBinding Content}"
Foreground="{TemplateBinding Foreground}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
</Border>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Code behind:
namespace MyProject
{
public partial class MyButton : UserControl
{
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(MyButton));
public CornerRadius CornerRadius
{
get => (CornerRadius)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
public MyButton() => InitializeComponent();
}
}
If I use the solution specified here User control with custom properties I get this problem Wpf - Custom control: How to override default properties?.
So, there is a solution that avoid both problems?
A custom Button should not be a UserControl, but instead directly derive from Button.
Add a "Custom Control (WPF)" to you Visual Studio Project and modify it like this:
public class MyButton : Button
{
static MyButton()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(MyButton),
new FrameworkPropertyMetadata(typeof(MyButton)));
}
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register(
nameof(CornerRadius), typeof(CornerRadius), typeof(MyButton));
public CornerRadius CornerRadius
{
get => (CornerRadius)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
}
Then change its default Style in the generated Themes\Generic.xaml file:
<Style TargetType="local:MyButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyButton">
<Border Name="ground"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding CornerRadius}">
<Label Name="content"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Content="{TemplateBinding Content}"
Foreground="{TemplateBinding Foreground}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
See Control Authoring Overview for details.

Parse XAML styles in code behind and load custom control

I have a c++ program that parse C# codes using Roslyn.
I need to convert my styles and custom controls to just "code-behind".
for example I have a simple custom control contains a button .
XAML Style :
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CUSTOM_LIBRARY_PARSE">
<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}">
<Button Background="#FF487DF0" >
<Label VerticalContentAlignment="Center" HorizontalContentAlignment="Center" OpacityMask="#FFC3C3C3" Content="{Binding text_of_button_Value, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:CustomControl1}}}" />
</Button>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Code-Behind of Control :
using System;
using System.Windows;
using System.Windows.Controls;
namespace CUSTOM_LIBRARY_PARSE
{
public class CustomControl1 : Control
{
public static readonly DependencyProperty text_of_button
= DependencyProperty.Register(
"text_of_button_Value",
typeof(string),
typeof(CustomControl1),
new PropertyMetadata(Environment.UserName)
);
public string text_of_button_Value
{
get { return (string)GetValue(text_of_button); }
set { SetValue(text_of_button, value); }
}
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
}
}
Now , I need to know how to embed xaml code in code behind as a string like :
string code_xaml = "<ResourceDictionary\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n xmlns:local=\"clr-namespace:CUSTOM_LIBRARY_PARSE\">\n <Style TargetType=\"{x:Type local:CustomControl1}\">\n <Setter Property=\"Template\">\n <Setter.Value>\n <ControlTemplate TargetType=\"{x:Type local:CustomControl1}\">\n <Border Background=\"{TemplateBinding Background}\"\n BorderBrush=\"{TemplateBinding BorderBrush}\"\n BorderThickness=\"{TemplateBinding BorderThickness}\">\n <Button Background=\"#FF487DF0\" >\n <Label VerticalContentAlignment=\"Center\" HorizontalContentAlignment=\"Center\" OpacityMask=\"#FFC3C3C3\" Content=\"{Binding text_of_button_Value, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:CustomControl1}}}\" />\n </Button>\n </Border>\n </ControlTemplate>\n </Setter.Value>\n </Setter>\n </Style>\n</ResourceDictionary>\n";
And next parse it with XamlParser and load it to customcontrol1
is that possible ?
thanks
The Answer is :
Create a public version of custom control :
public CustomControl1()
{
}
Create a public version of custom control :
public CustomControl1()
{
ResourceDictionary Parse_Resource = XamlReader.Parse(code_xaml) as ResourceDictionary;
this.Resources = Parse_Resource;
}
Solved :D

User control with WebBrowser in 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.

Categories