I'm new to VS and XAML and I was following a tutorial on using control templates to
customize buttons.
<Window x:Class="Kromelodeon.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:Kromelodeon"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Button Content="Button" HorizontalAlignment="Left" Margin="399,70,0,0" VerticalAlignment="Top" Width="75"/>
<Button.Template>
<ControlTemplate TargetType="Button">
<Ellipse Fill="Orange"></Ellipse>
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"></ContentPresenter>
</ControlTemplate>
</Button.Template>
</Grid>
For some reason, I'm getting an error that "Template" is not recognizable
or accessible on line 10
Can anyone point out why? I was originally trying to make four-sided diamond-shaped buttons using the
Path controls ie M 0,0 100,100 etc but got so many error codes I decided to start over with something simpler. This is a WPF desktop app.
Please help.
Your ControlTemplate needs to be inside the begin and end tags of the button like below.
Also, your ControlTemplate needs to have a root element. In this case I used a Grid which is very common.
Elements that sit on a line by themselves and have no children (nested elements) can be closed off with />
<Button Content="Button"
HorizontalAlignment="Left"
Margin="399,70,0,0"
VerticalAlignment="Top"
Width="75">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="Orange" />
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
Related
The short version of my question is: Can properties of the UserControl be made available to the children of the UserControl without applying to the UserControl at the same time?
The long version: I am trying to create a "ButtonInput" which is a text box with a bitmap button at the right side, inside of the text box's border. This is pretty much how the search boxes look on many web sites (or in Visual Studio), with a magnifying glass at the right side.
The UserControl definition is:
<UserControl x:Class="Test.Controls.ButtonInput"
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:Test.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="Transparent">
<Border
Name="Border"
CornerRadius="6"
Padding="4"
Margin="2 2 2 2"
Background="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
BorderBrush="{Binding Path=BorderBrush, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
BorderThickness="1"
>
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="tbInput"
Grid.Column="0"
MaxLines="1"
Background="Transparent"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
Text="{Binding Path=Text, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
BorderThickness="0"/>
<Button Width="24" Grid.Column="1" Click="Button_Click">
<Button.Template>
<ControlTemplate>
<Image x:Name="imgIcon"
Source="{Binding Path=Source, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}" />
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</Border>
</Grid>
</UserControl>
I place this control in a test Window.
<Window x:Class="Test.TestWindow"
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:Test"
xmlns:controls="clr-namespace:Test.Controls"
mc:Ignorable="d"
Title="TestWindow" Height="450" Width="800">
<Grid>
<StackPanel Orientation="Horizontal" Height="380" Width="402">
<Label Content="Password" Width="75" VerticalAlignment="Center"/>
<controls:ButtonInput x:Name="biTest" Source="Resources/img/password.png" Width="300" Height="35" Background="Orange" Foreground="Red" BorderBrush="Black" ButtonClick="ButtonInput_ButtonClick" />
</StackPanel>
</Grid>
</Window>
The problem I have is that I expect to have only what is inside the border colored orange, but instead the orange bleeds outside the border. I traced the problem to the way the Live Visual Tree looks like:
(ButtonInput)
(Border)
(ContentPresenter)
(Grid)
Border (Border)
(Grid)
tbInput (TextBox)
(Button)
The first Border is not in my control definition, but its background is Orange as inherited from the ButtonInput.
I did try an alternative: instead of using child controls for the content of the UserControl, I used a ControlTemplate with the same content. In this case, the executable looked OK (rounded rectangle with black border and orange background, no bleeding outside the border), but the designer in Visual Studio does not show anything. There is literally a blank space where the ButtonInput should be.
So, is there a way to prevent the properties set on the UserControl to apply to the first Border? Background is one example but there are other properties that I want to make use of the same way.
What's happening here is that your "ButtonInput" control isn't actually a button, it's a user control which just so happens to have a button on it. So when you set the background in the <controls:ButtonInput> tag on your main window you're effectively saying "ignore everything this user control says about the color of it's entire background because I'm now overriding it".
There are several ways around this, but the easiest one from the UserControl's perspective is to use the one last weapon in its arsenal: the template. Overriding the template in a control effectively says "I'm no longer going to be displayed the way a control of my type normally is, so all the usual settings won't apply unless I explicitly use them. That's as simple as doing this in your ButtonInput xaml:
<UserControl.Template>
<ControlTemplate>
<!-- all your old xaml code goes here -->
<Grid Background="Transparent">
<Border
Name="Border"
CornerRadius="6"
Padding="4"
<!-- etc -->
</ControlTemplate>
</UserControl.Template>
Which results in the following:
Truth be told, there are few cases in WPF where custom controls are actually needed, and this is almost certainly one of them. WPF is more than capable of supporting functionality like this with styles and templates alone. But this answer should suit your needs in the short term.
EDIT: If you want the control to be visible in the designer then populate it with a regular control and template that instead, it's what you probably should be doing anyway. Now your xaml should look like this:
<UserControl x:Class="WpfTestApp.Controls.ButtonInput"
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:WpfTestApp.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
x:Name="_this">
<UserControl.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Grid Background="Transparent">
<Border
Name="Border"
CornerRadius="6"
Padding="4"
Margin="2 2 2 2"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1"
>
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="tbInput"
Grid.Column="0"
MaxLines="1"
Background="Transparent"
Text="{Binding ElementName=_this, Path=Text, Mode=TwoWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
Foreground="{TemplateBinding Foreground}"
BorderThickness="0" Margin="0,-1,0,1"/>
<Button Width="24" Grid.Column="1">
<Button.Template>
<ControlTemplate>
<Image x:Name="imgIcon" />
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</Border>
</Grid>
</ControlTemplate>
</UserControl.Resources>
<Button x:Name="biTest" Width="300" Height="35" Background="Orange" Foreground="Red" BorderBrush="Black" Template="{StaticResource ButtonTemplate}" />
</UserControl>
You haven't addressed the Text binding in your question, the code above is expecting a dependency property in the UserControl code behind:
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ButtonInput), new PropertyMetadata(String.Empty));
And you now use it like this:
<controls:ButtonInput x:Name="biTest" Width="300" Height="35" Text="{Binding MyText, Mode=TwoWay}" />
Consider I have 4 Window on my project and I try to provide specific Closing button and one Title
How could I make a object of window and all of window use it as Pattern.
Here is Example of what we have for pattern window:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowStyle="None" AllowsTransparency="True" >
<Grid>
<Button Content="Close" Height="40" VerticalAlignment="Top" HorizontalAlignment="Right"/>
<TextBlock VerticalAlignment="Top" HorizontalAlignment="Center" X:Name="WindowTitle/>
</Grid>
</Window>
How could I use for all of my Window as pattern. Thanks
Actually, there is no need to write a parent window. You can use Style and Template instead. It's more convenient and is recommended by Microsoft WPF Team.
Write the code below into your App.xaml and you'll get the picture above:
<Application x:Class="Walterlv.Demo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
.........>
<Application.Resources>
<Style x:Key="Style.Window.Default" TargetType="Window">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Window">
<Grid Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Close" Height="40" VerticalAlignment="Top" HorizontalAlignment="Right"/>
<TextBlock Grid.Row="0" VerticalAlignment="Top" HorizontalAlignment="Center"
Text="{TemplateBinding Title}"/>
<Border Grid.Row="1" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<!-- This is the container to host your Window.Content -->
<ContentPresenter/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>
And you can use only one property Style to share such a "pattern":
<Window x:Class="Walterlv.Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Style="{StaticResource Style.Window.Default}">
</Window>
You can define different kinds of styles in the App.xaml file and select anyone in your XxxWindow.xaml you need.
The Setup
I have the following style that I apply to most of the windows in my application:
<ResourceDictionary x:Class="MyNamespace.ChromeWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="CustomChromeTest" TargetType="{x:Type Window}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid x:Name="GridMain" Background="{StaticResource MainFormColor}">
<ContentPresenter HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
I use it to customize the window chrome around my window (I have removed that part) so all the actual contents of the window go inside the content presenter. I use this style like so:
<Window x:Class="MyNamespace.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"
mc:Ignorable="d"
Title="Window1" Height="300" Width="300"
Style="{DynamicResource CustomChromeTest}">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/WPFControlLibrary;component/Resources/ChromeWindow.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
</StackPanel>
This XAML above produces a window that looks like this:
The Problem
In a normal window, when the user is tabbing through the controls, the current button is highlighted to show the user the current button. Note the border around the 3rd button below.
For some reason, the moment I use my style, this feature disappears and there is no indication of which button has focus, even though the user can tab like normal. Why is this and how can I restore the built-in functionality.
Please Note
I use this style with dozens of windows and hundreds of controls. I do not want to use a style on every control with a trigger that displays a border when the control has focus. I want to restore the default functionality that was being used before I applied my custom window style.
You'll just need to define the ContentPresenter as AdornerDecorator for Window and it will work as intended. Which I didn't figure out at first either apparently :)
Style;
<Style x:Key="CustomChromeTest" TargetType="{x:Type Window}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid x:Name="GridMain" Background="Yellow">
<AdornerDecorator>
<ContentPresenter/>
</AdornerDecorator>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and your window...
<Window
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:WpfApplication1"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero2" x:Name="Testeroo"
x:Class="WpfApplication1.MainWindow"
mc:Ignorable="d" Style="{StaticResource CustomChromeTest}"
Title="MainWindow" Height="550" Width="750">
<StackPanel>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
</StackPanel>
</Window>
Hope this helps, cheers.
I want to change my form border and Title Bar and fount this solution.
So after add this into my XAML (i am using the first solution in the first answer) my application running and i can see the Style changed but after few seconds i can see this exception in the designer:
My application still run and show the new style but this is happening again and again, i try to remove and add changes several times but this error still jump after a while.
Update
this is the code that added to XAML:
<Window x:Class="CSharpWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" >
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="{Binding ActualHeight,ElementName=titlebar}"/>
</WindowChrome.WindowChrome>
<DockPanel LastChildFill="True">
<Border Background="LightBlue" DockPanel.Dock="Top" Height="25" x:Name="titlebar">
<TextBlock Text="{Binding Title, RelativeSource={RelativeSource FindAncestor,AncestorType=Window},FallbackValue=Title}"
Margin="10,0,0,0"
VerticalAlignment="Center">
<TextBlock.Effect>
<DropShadowEffect Color="White" ShadowDepth="3"/>
</TextBlock.Effect>
</TextBlock>
</Border>
<Border BorderBrush="LightGray" BorderThickness="1" Padding="4">
<TextBlock Text="Window content"/>
</Border>
</DockPanel>
</Window>
I have a simple custom window (XAML below).
When first loaded, it will add a user control to the grdContainer.Children collection.
User selection/action will cause other user controls to added/removed to the children collection. (one loaded at a time). What I am attempting to do is provide a simple animation as the new control is loaded, something like a 45degree swipe from top left to bottom right.
If anyone can point me in the right direction, I would appreciate it.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WinClientFolder"
x:Name="WinClientFolder"
Title="MainWindow"
Width="450" Height="300" AllowsTransparency="True" WindowStyle="None" ResizeMode="CanResizeWithGrip">
<Window.Background>
<SolidColorBrush />
</Window.Background>
<Grid x:Name="LayoutRoot">
<Border BorderBrush="Black" BorderThickness="2,2,2,0" Margin="18,13,0,0" CornerRadius="10,10,0,0" Background="#FFCCC523" Height="32" VerticalAlignment="Top" HorizontalAlignment="Left" Width="179" Name="FolderTab">
<Grid Height="25" HorizontalAlignment="Left" Name="grdFolderTop" VerticalAlignment="Top" Width="175">
<TextBlock x:Name="txtClientName" Height="34" TextWrapping="NoWrap" Width="Auto" FontSize="18" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5,0,0,0"><Run Text="Doe, John Family " /><LineBreak /><Run /></TextBlock>
</Grid>
</Border>
<Border BorderBrush="Black" BorderThickness="2,1,6,2" Margin="0,45,0,0" Background="#FFCCC523" CornerRadius="10,10,0,0" Grid.ColumnSpan="2" Name="FolderBody">
<Grid Height="Auto" Name="grdContainer" Width="Auto" />
</Border>
</Grid>
I asked a somewhat similar question in this post. I can highly recommend this Transitionals framework. It's simple to use and looks great.