In UWP I have created CustomTextBox which is derived from TextBox control. In my CustomTextBox, I have used various properties but some properties are working and some are not working.
Below properties are working fine,
Width Height BorderBrush, etc,.
Below properties are not working,
Header Text, etc,. Please find code snippet on below,
MyTextBox.cs
public sealed class MyTextBox : TextBox
{
public MyTextBox()
{
this.DefaultStyleKey = typeof(MyTextBox);
}
}
Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SfMaskedEdit_header">
<Style TargetType="local:MyTextBox" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyTextBox">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
MainPage.xaml
<Page
x:Class="SfMaskedEdit_header.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SfMaskedEdit_header"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="grid1">
<local:MyTextBox x:Name="myTextBox" Text="Hello" Header="MyTextBox" Width="200" Height="40"
BorderBrush="Blue" BorderThickness="2" Background="Pink"/>
</Grid>
</Page>
Please use the below sample for further information,
Sample: MyTextBox
The reason is that you have overridden the default template and hence removed all the elements that normally make up a TextBox.
To understand this, it is important to make it clear that UWP controls usually just provide a behavior, but are themselves made up of multiple other controls in their template (the terminology is usually that XAML controls are look-less by default). And these controls are providing the visual representation of the control. For example, in the case of TextBox, the template is made up of Border for the borders around it, TextBlock for the placeholder text, Button for clearing out the content, a ScrollViewer where the Text input is rendered and a ContentPresenter for the header and so on.
Your custom TextBox is in fact just the Border itself, which means you have essentially lost the capabilities you mentioned because there are no controls to surface them visually.
To fix your problem, I suggest starting with the default TextBox template (by copying and pasting it to your own style. And then just editing the parts that you want to change. This way you will start from the fully functional state and can decide what to change while retaining the capabilities of the control.
You can find the default template in C:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\{version}\Generic\generic.xaml. You can search for <Style TargetType="TextBox"> to find the default TextBox style and template.
Related
I need to create a custom control similar to WPF GroupBox. I started from the standard WPF Custom Control Library template in VS 2015 and defined my CustomGroupBox control like this:
public class CustomGroupBox : ContentControl
{
static CustomGroupBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomGroupBox), new FrameworkPropertyMetadata(typeof(CustomGroupBox)));
}
}
Then added the following minimal set of lines to develop my custom GroupBox according to the specification:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomGroupBox">
<Style TargetType="{x:Type local:CustomGroupBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomGroupBox}">
<Border Background="{TemplateBinding Background}"
BorderBrush="Gray" BorderThickness="3" CornerRadius="3">
<ContentControl />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
To debug and develop, I created a test form for my custom control:
<Window x:Class="CustomGroupBoxClient.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:CustomGroupBoxClient"
xmlns:ctrl="clr-namespace:CustomGroupBox;assembly=CustomGroupBox"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ctrl:CustomGroupBox Margin="5">
<StackPanel Orientation="Vertical">
<TextBlock>Text Block #1</TextBlock>
<TextBlock>Text Block #2</TextBlock>
</StackPanel>
</ctrl:CustomGroupBox>
</Grid>
</Window>
However, when I launch this form, I see the border of my custom control but not the content (2 TextBlock's):
I've re-read many manuals and articles related to this topic, but still can't figure out why ContentControl in my ControlTemplate does not display the specified content. How to solve my problem?
Try using ContentPresenter instead of ContentControl in your template:
<ContentPresenter />
By default, ContentPresenter finds the Content property of its templated parent and displays whatever it finds there. You could change the name of the property it looks for by changing its ContentSource value...
<ContentPresenter ContentSource="FooBar" />
...but since you're inheriting from ContentControl, the default is probably what you want.
I am trying to create my own expandable/collapsible menu (creatively called ExpandingMenu) in my first WPF project. I already have one user control consisting of a 2-row Grid (row 1 is a button to collapse and expand the control, row 2 is a StackPanel for rotating ToggleButtons, which is where I'm currently stuck). For my rotating buttons, I have just decided to make them their own UserControls as well.
The Buttons (I'm calling them ExpandingMenuButtons) are no more than a ToggleButton in a 1x1 Grid (I'm thinking of doing it this way since I may want to add some extra custom logic to these buttons after I get the standard behavior sorted out). I can add them to my menu control successfully, I can even get them to rotate via a RenderTransform on the Grid.
However, as you can probably tell, they swing up when they rotate. This causes them to not only be too high, but they also likely extend to far up.
This is what I currently have, before attempting rotations, it is behaving as expected.
This is what I'm trying to accomplish (edited using the magic of paint). I can get this correct behavior in my Menu control (tan areas), but I've mangled the expand/contract event in the meantime for testing purposes...
What I can do when I rotate 1 button (Like I mentioned earlier, I've mangled some behavior for my testing purposed, so each button is set to rotate on click, not all at once like you may expect). As you can see, this button has swung out from where it originally was. buttons higher up will swing partially/completely out of view. Instead, I would like them to rotate into the proper place. once I get one to work right, I assume it will be simple to get the rest behaving the same way, which I why I'm trying things this way..
My button code is below:
<UserControl x:Class="App.Controls.ExpandingMenuButton"
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:App.Controls"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="100">
<Grid Name="ButtonGrid" Height="30">
<ToggleButton Name="MenuButton" Background="Aqua" BorderThickness="0 0 0 1" Click="MenuButton_Click" Content="TEST"></ToggleButton>
</Grid>
</UserControl>
the only "real" code in ExpandingMenuButton.xaml.cs so far:
private void MenuButton_Click(object sender, RoutedEventArgs e)
{
//I know this is not practical, it is used for quick testing.
ButtonGrid.RenderTransform = new RotateTransform(-90);
}
My menu code so far:
<UserControl x:Class="App.Controls.ExpandingMenu"
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:App.Controls"
mc:Ignorable="d"
Name="ucExpandingMenu"
MinWidth="32"
d:DesignHeight="300" d:DesignWidth="100">
<UserControl.Resources>
<SolidColorBrush x:Key="BackColor" Color="PeachPuff"/>
<!-- This style is used for buttons, to remove the WPF default 'animated' mouse over effect. http://stackoverflow.com/a/4182205/2957232 -->
<Style x:Key="ExpandButtonStyle" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border"
BorderThickness="0 0 0 1"
BorderBrush="Black"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="Black" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Name="MenuPanel" Width="100" HorizontalAlignment="Left" Background="{DynamicResource BackColor}" Grid.Row="1">
<!--Contents will go here-->
</StackPanel>
<Button Style="{StaticResource ExpandButtonStyle}" Width="100" Height="32" FontSize="18" VerticalAlignment="Center" HorizontalAlignment="Stretch" Panel.ZIndex="1" Background="{DynamicResource BackColor}" BorderThickness="0" Click="Button_Click" Content="ยป"></Button>
<Button Name="DummyFocus" Panel.ZIndex="0" Height="0" Width="0"></Button>
</Grid>
</UserControl>
And again, the only "real" code in this class so far:
private void Button_Click(object sender, RoutedEventArgs e)
{
MenuPanel.Children.Add(new ExpandingMenuButton("TEST ITEM"));
}
Please excuse my lack of WPF knowledge, I'm trying to come from a world of Winforms, where even there I have a lack of knowledge when it comes to this sort of thing. I know the code looks kinda funny, but hopefully the images show what I'm after here. So far I'm just testing this in a dummy window with only a grid and the HorizontalAlignment set to "Left". Nothing fancy.
Use LayoutTransform. Using RenderTransform does not affect how other controls (including parent) are being rendered/laid out; LayoutTransform does.
Shift the transform to the whole UserControl. You can probably specify directly in XAML instead.
Example:
<UserControl.LayoutTransform>
<RotateTransform Angle="-90" />
</UserControl.LayoutTransform>
I've create a custom control which inherit from WPF TextBox.
My Control Template simply add a small button on textbox in order to delete its text quicker.
However, I've noticed that when my textBox got the focus, its border doesn't change (blue color) as is the case for classic textbox.
I would preserver all aspect of original textBox, just like the border when the control get focus.
Am I missing something?
##EDIT
<TextBox x:Class="XTextBox.WKTextBox"
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"
Height="23" Width="200"
>
<TextBox.Resources>
<ControlTemplate x:Key="IconButton" TargetType="{x:Type ToggleButton}">
<Border>
<ContentPresenter />
</Border>
</ControlTemplate>
</TextBox.Resources>
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Border BorderThickness="1" BorderBrush="DarkGray">
<ScrollViewer x:Name="PART_ContentHost" />
</Border>
<ToggleButton Template="{StaticResource IconButton}"
MaxHeight="21"
Margin="-1,0,0,0"
Name="imgButton"
Focusable="False"
IsChecked="False">
<Image Name="imgClearText" Source="Images\x.png" Stretch="Uniform" Opacity="0.5" Visibility="Visible" HorizontalAlignment="Right" >
</Image>
</ToggleButton>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Style>
Unfortunately, you can't simply Replace part of default template in WPF without loosing functionallity.
I believe the easiest solution would be to donwload Blend (it comes with VS2015). Open it, create an emty textbox and edit its template:
Blend will make a copy of default template, so you won't loose any of your default behaviour, like selection, focus etc.
Then you can save a project, open it in VS and refactor it as you want. Like moving style to dictionary or something.
You can manually get the same effect by adding handlers for the GotFocus & LostFocus events of the Border and set the highlight colors you want there.
<Border BorderThickness="1" BorderBrush="DarkGray" LostFocus="Border_LostFocus" GotFocus="Border_GotFocus">
and in your .cs file
private void Border_LostFocus(object sender, RoutedEventArgs e)
{
((Border)sender).BorderBrush = new SolidColorBrush(Colors.DarkGray);
}
private void Border_GotFocus(object sender, RoutedEventArgs e)
{
((Border)sender).BorderBrush = new SolidColorBrush(Colors.LightBlue);
}
I've created a custom WPF user control. The problem is, that sometimes I need a BorderThickness of 0 and sometimes a BorderThickness of 1.
<UserControl ...>
<clay:TextBox x:Name="ClayTextBox"
BorderThickness="1" >
</clay:TextBox>
</UserControl>
If I'm using the control in a xaml document like this:
<clay:TextBox x:Name="ClayTextBox"
BorderThickness="0" >
</clay:TextBox>
... the Border is always 1. How can I solve that?
In your custom control template style, you should set the parent container control as border and then use template binding to bind the border thickness. Here I've assumed that your CustomControl inherits a control that has BorderThickness as a property.
<ControlTemplate TargetType="{x:Type clay:TextBox}">
<Border BorderThickness="{TemplateBinding BorderThickness}">
//Remaining xaml that makes up your custom control.
</Border>
</ControlTemplate>
Have your border Bind its BorderThickness propety to the UserControls one like this:
<UserControl x:Class="UseRcontrolWithProperty.UserControl1"
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" x:Name="this"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Border BorderThickness="{Binding ElementName=this, Path=BorderThickness}"></Border>
</Grid>
</UserControl>
that way changing the BorderBrush on the UserControl will change the border brush of the internal border.
i have to develop a wpf control which shall have the same behaviour as the well known border.
The shape of the control shall be the new part. Every definable closed path shall be used to define the appearence of the control.
I need help to achieve this.
Currently i have no idea how to interchange the rectangle(??) with the closed path.
Any help would be highly appreciated.
Edit Here goes direct answer to your question. We will write a ContentControl derived class, with very flexible form of border. Basis for this idea lies in OpacityMask.
If you would like to know more about this approach take a look on example from Chris Cavanagh's solution for rounded corners.
Step 1. Create custom control FreeFormContentControl:
FreeFormContentControl.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfApplication5
{
public class FreeFormContentControl : ContentControl
{
public Geometry FormGeometry
{
get { return (Geometry)GetValue(FormGeometryProperty); }
set { SetValue(FormGeometryProperty, value); }
}
public static readonly DependencyProperty FormGeometryProperty =
DependencyProperty.Register("FormGeometry", typeof(Geometry), typeof(FreeFormContentControl), new UIPropertyMetadata(null));
static FreeFormContentControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(FreeFormContentControl),
new FrameworkPropertyMetadata(typeof(FreeFormContentControl))
);
}
}
}
Themes\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:WpfApplication5">
<Style TargetType="{x:Type local:FreeFormContentControl}">
<Setter Property="FormGeometry"
Value="M0,0 L1,0 1,1 0,1z" />
<Setter Property="Background"
Value="Black" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:FreeFormContentControl}">
<Grid>
<Path Name="mask"
Data="{TemplateBinding FormGeometry}"
Fill="{TemplateBinding Background}" />
<Grid>
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=mask}" />
</Grid.OpacityMask>
<ContentPresenter />
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
More reading on custom controls can be found on CodeProject.
Step 2. Usage. Now you can place any content inside this control. Its default shape is rectangle. So the following code will result in regular StackPanel UI:
<Window x:Class="WpfApplication5.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cc="clr-namespace:WpfApplication5"
Title="Window1"
Height="300"
Width="300">
<Grid>
<cc:FreeFormContentControl>
<StackPanel>
<Button Content="Any" />
<Button Content="Content" />
<TextBlock Text="Goes" />
<TextBox Text="Here" />
</StackPanel>
</cc:FreeFormContentControl>
</Grid>
</Window>
But if you define custom FormGeometry you'll get custom shape. For example, the following form geometry presents inner controls inside a diamond:
<cc:FreeFormContentControl FormGeometry="M0,0.5 L0.5,0 1,0.5 0.5,1z">
To read more about geometry definition from XAML, read corresponding section on MSDN: Path Markup Syntax.
The last thing to mention here, is that you don't have to specify or calculate concrete pixel values of your FormGeomtry. Grid makes this trick possible. So think of it as of percentage. I.e. 1 == full width or height. 0.5 == half of available width/hight and so on.
Hope this helps.