How to get image source in Control Template - silverlight

I've added one button like this:
<Button x:Name="myButton"
Style="{StaticResource myButtonStyle}"
Height="36"
VerticalAlignment="Top"
Click="myButton_Click">
<Grid>
<Image Height="*" Width="31" Source="{Binding Path=Image}" />
<TextBlock Text="{Binding Path=DisplayName}" HorizontalAlignment="Center" />
</Grid>
</Button>
Where 'Image' is the source of the required image in string. And the style is as follows:
<Style x:Key="myButtonStyle"
TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="myButtonRootBorder">
<StackPanel Orientation="Horizontal">
<Image Source="{??}" Width="{??}" Height="{??}" />
<!--ContentPresenter-->
<ContentPresenter Grid.Column="1"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}" />
</StackPanel
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now how to set the height, width and source of the image in the control template.
Please help. Thanks in advance.

For width and height you can use {TemplateBinding Width} and {TemplateBinding Height}. If you want the image to be customizable you should inherit the button class and add an imagesource property:
public class ImageButton : Button {
public ImageSource ImageSource
{
get { return (ImageSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for ImageSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(ImageButton), new UIPropertyMetadata(null));
}
Then you can use {TemplateBinding ImageSource} for the image.

Related

wpf prism and custom control

i need help with creation custom control and prism library.
custom control must have two columns. And using prism library i want
insert in region some view
what i have:
public class MyContentControl : Control
{
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(object),
typeof(MyContentControl), null);
[Bindable(true)]
public object Content
{
get { return GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public static readonly DependencyProperty Content2Property = DependencyProperty.Register("Content2", typeof(object),
typeof(MyContentControl), null);
[Bindable(true)]
public object Content2
{
get { return GetValue(Content2Property); }
set { SetValue(Content2Property, value); }
}
}
and ResoureDictionary
<Style TargetType="{x:Type local:MyContentControl}">
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyContentControl}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinition>
<ContentControl Grid.Column="0" Content="{TemplateBinding Content}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="IndianRed"/>
<ContentControl Grid.Column=1 Content="{TemplateBinding Content2}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="Aqua" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
what i want is use it like
<MyContentControl>
<MyContentControl.Content1>
<ContentControl prism:RegionManager.RegionName="{x:Static constants:RegionNames.Content1_Region}"/>
</MyContentControl.Content1>
<MyContentControl.Content2>
<ContentControl prism:RegionManager.RegionName="{x:Static constants:RegionNames.Content2_Region}"/>
</MyContentControl.Content2>
</MyContentControl >

Custom control does not allow to focus its children in design view

I struggle for a while with no luck. My custom control is based on ContentControl, and similar to HeaderedContentControl, just with footer too.
If element in header of original HeaderedContentControl is clicked in design view, in example:
<HeaderedContentControl>
<HeaderedContentControl.Header>
<Button Content="header"/>
</HeaderedContentControl.Header>
<Button>Content</Button>
</HeaderedContentControl>
Clicking on "header" button will centre xaml code on <Button Content="header"/>.
My control:
public class TestControl : ContentControl
{
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof (object), typeof (TestControl), (PropertyMetadata) new FrameworkPropertyMetadata((object) null));
[Bindable(true)]
[Category("Content")]
public object Header
{
get { return (object) GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
}
and styling (taken from HeaderedContentControl:
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type cbr:TestControl}">
<StackPanel>
<ContentPresenter Content="{TemplateBinding cbr:TestControl.Header}" ContentTemplate="{TemplateBinding HeaderedContentControl.HeaderTemplate}" ContentStringFormat="{TemplateBinding HeaderedContentControl.HeaderStringFormat}" ContentSource="Header" />
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
if "header" button is clicked (in design view) in my control, xaml centres on
<cbr:TestControl> instead of <Button Content="header"/>
<cbr:TestControl>
<cbr:TestControl.Header>
<Button Content="header"/>
</cbr:TestControl.Header>
<Button>Content</Button>
</cbr:TestControl>

UserControl multiple datatemplate + templateselector

I need to show data inside a usercontrol in different ways depending on a flag.
To achieve this i tried the following, but using this control in the main view shows nothing.
<UserControl DataContext="**self**">
<UserControl.Resources>
<DataTemplate x:Key="mouseInputTemplate">
<TextBlock HorizontalAlignment="Center"><Run Text="{Binding Text}" /></TextBlock>
</DataTemplate>
<DataTemplate x:Key="touchInputTemplate">
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Image Source="{Binding ImageUri}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" />
<TextBlock HorizontalAlignment="Center"><Run Text="{Binding Text}" /></TextBlock>
</StackPanel>
</DataTemplate>
<local:InputModeDataTemplateSelector x:Key="inputModeTemplateSelector"
MouseInputModeTemplate="{StaticResource mouseInputTemplate}"
TouchInputModeTemplate="{StaticResource touchInputTemplate}" />
</UserControl.Resources>
<ContentControl HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch" ContentTemplateSelector="{StaticResource inputModeTemplateSelector}" />
</UserControl>
What am i doing wrong?
Is there a better way to achieve that?
Thank to EdPlunkett and more research i found out it is better to
use a ContentPresenter here and instead of binding on DataContext=this bind like this (as alsways suggested when writing a UserControl)
DataContext="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type yourType}}}"
Code:
<UserControl.Resources>
<DataTemplate x:Key="touchInputTemplate">
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Image Source="{Binding ImageUri}" Width="64" Height="64" />
<TextBlock HorizontalAlignment="Center" Text="{Binding Text}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="mouseInputTemplate">
<TextBlock HorizontalAlignment="Center" Text="{Binding Text}" />
</DataTemplate>
<local:InputModeDataTemplateSelector x:Key="inputModeTemplateSelector"
MouseInputModeTemplate="{StaticResource mouseInputTemplate}"
TouchInputModeTemplate="{StaticResource touchInputTemplate}" />
</UserControl.Resources>
<Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type yourType}}}">
<ContentPresenter Content="{Binding}" ContentTemplateSelector="{StaticResource inputModeTemplateSelector}">
</Grid>
Your ContentPresenter idea is the correct way to do it with a DataTemplateSelector, and I should have thought of it myself.
But here's yet another way to do it, which unlike my first answer, actually solves all the problems you're having:
XAML (in practice the Style would probably be defined in a separate ResourceDictionary):
<Window
x:Class="TestApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestApplication"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
Title="MainWindow" Height="350" Width="525"
>
<Window.Resources>
<Style TargetType="local:TestControl">
<Setter Property="Background" Value="Gainsboro" />
<Style.Triggers>
<!-- The 0 value for the InputMode enum is Mouse, so this will be the default. -->
<Trigger Property="InputMode" Value="Mouse">
<Setter Property="Background" Value="Wheat" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TestControl}">
<Grid Background="{TemplateBinding Background}">
<TextBlock HorizontalAlignment="Center"><Run Text="{TemplateBinding Text}" /></TextBlock>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="InputMode" Value="Touch">
<Setter Property="Background" Value="LightSkyBlue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TestControl}">
<Grid Background="{TemplateBinding Background}">
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Image
Source="{TemplateBinding ImageUri}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="{TemplateBinding ImageWidth}"
Height="{TemplateBinding ImageHeight}"
/>
<TextBlock HorizontalAlignment="Center"><Run Text="{TemplateBinding Text}" /></TextBlock>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<local:TestControl
ImageHeight="100"
ImageWidth="100"
Text="This is the test control"
ImageUri="http://www.optimizeagency.com/wp-content/uploads/2015/09/GoogleLogo.jpg"
/>
</Grid>
</Window>
C#:
using System;
using System.Windows;
using System.Windows.Controls;
namespace TestApplication
{
class TestControl : Control
{
public TestControl()
{
// If input mode may change at runtime, you'll need an event that fires when that
// happens and updates this property.
// UIUtilities.GetInputMode() is just a stub in this example.
InputMode = UIUtilities.GetInputMode();
}
#region InputMode Property
public InputMode InputMode
{
get { return (InputMode)GetValue(InputModeProperty); }
set { SetValue(InputModeProperty, value); }
}
public static readonly DependencyProperty InputModeProperty =
DependencyProperty.Register("InputMode", typeof(InputMode), typeof(TestControl),
new PropertyMetadata(InputMode.Mouse));
#endregion InputMode Property
#region Text Property
public String Text
{
get { return (String)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(String), typeof(TestControl),
new PropertyMetadata(null));
#endregion Text Property
#region ImageUri Property
// The TemplateBinding in the template can't coerce a string to an
// ImageSource, so we have to make that happen elsewhere.
public ImageSource ImageUri
{
get { return (ImageSource)GetValue(ImageUriProperty); }
set { SetValue(ImageUriProperty, value); }
}
public static readonly DependencyProperty ImageUriProperty =
DependencyProperty.Register("ImageUri", typeof(ImageSource), typeof(TestControl),
new PropertyMetadata(null));
#endregion ImageUri Property
#region ImageHeight Property
public float ImageHeight
{
get { return (float)GetValue(ImageHeightProperty); }
set { SetValue(ImageHeightProperty, value); }
}
public static readonly DependencyProperty ImageHeightProperty =
DependencyProperty.Register("ImageHeight", typeof(float), typeof(TestControl),
new PropertyMetadata(float.NaN));
#endregion ImageHeight Property
#region ImageWidth Property
public float ImageWidth
{
get { return (float)GetValue(ImageWidthProperty); }
set { SetValue(ImageWidthProperty, value); }
}
public static readonly DependencyProperty ImageWidthProperty =
DependencyProperty.Register("ImageWidth", typeof(float), typeof(TestControl),
new PropertyMetadata(float.NaN));
#endregion ImageWidth Property
}
#region This stuff belongs in a different file
public static class UIUtilities
{
public static InputMode GetInputMode()
{
// Here you'd do whatever you're already doing to detect the input mode
return InputMode.Touch;
}
}
public enum InputMode
{
Mouse,
Touch
}
#endregion This stuff belongs in a different file
}

Align two pieces of text separably in a WPF button

I have a reasonably simple button ControlTemplate to style a button.
I have been asked to align a portion of the text for the button to the right of the button. Therefore Some text will be aligned left and some right.
A pointer to an approach for this would be appreciated.
This is what I have so far:
<ControlTemplate x:Key="ListItemNameTemplate" TargetType="Button">
<Grid Height="40">
<Border Width="200"
x:Name="BgEnabled"
HorizontalAlignment="Center"
Margin="1,1,1,1"
Background="YellowGreen">
<StackPanel Orientation="Vertical">
<TextBlock Width="150"
x:Name="textBlock"
Text="{TemplateBinding Content}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="White"
FontSize="24"
FontWeight="Bold"/>
<TextBlock Width="50"
x:Name="textBlock1"
Text="{TemplateBinding Content}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Foreground="White"
FontSize="24"
FontWeight="Bold"/>
</StackPanel>
</Border>
</Grid>
</ControlTemplate>
however:
a. The second textblock does not display.
b. I need to specify the content for the second textblock differently than "Content".
You can subclass Button to introduce a new dependency property for the right-aligned text, you will be stuck with the Content property though (you could create two new properties and throw an exception if Content is set though).
To get the layout right you should either use a Dockpanel (dock left and right, LastChildFill set to false) or a Grid (with three columns, middle takes rest, left & right is auto-sized).
Like this:
<Window.Resources>
<ControlTemplate TargetType="{x:Type Button}"
x:Key="MyButtonTemplate">
<Border>
<DockPanel LastChildFill="True">
<TextBlock Text="{TemplateBinding Content}"
DockPanel.Dock="Top"/>
<TextBlock Text="{TemplateBinding Content}"
TextAlignment="Right" />
</DockPanel>
</Border>
</ControlTemplate>
</Window.Resources>
<Button Template="{StaticResource MyButtonTemplate}">
Hello World
</Button>
Looks like:
If you want the second text different then just create a second property. I would create an attached dependency property so you can still use TextBox without having to subclass it and screw up all the UI elements in your project. Use the snippet "propa" to get started in Visual Studio. It's easy. See here: http://msdn.microsoft.com/en-us/library/ms749011.aspx
Like this:
public class MyButtonThing
{
public static string GetText2(DependencyObject obj)
{
return (string)obj.GetValue(Text2Property);
}
public static void SetText2(DependencyObject obj, string value)
{
obj.SetValue(Text2Property, value);
}
public static readonly DependencyProperty Text2Property =
DependencyProperty.RegisterAttached("Text2",
typeof(string), typeof(System.Windows.Controls.Button));
}
And this:
<Window.Resources>
<ControlTemplate TargetType="{x:Type Button}"
x:Key="MyButtonTemplate">
<Border>
<DockPanel LastChildFill="True">
<TextBlock Text="{TemplateBinding Content}"
DockPanel.Dock="Top"/>
<TextBlock TextAlignment="Right" Text="{Binding
RelativeSource={RelativeSource AncestorType=Button},
Path=(local:MyButtonThing.Text2)} " />
</DockPanel>
</Border>
</ControlTemplate>
</Window.Resources>
<Button Template="{StaticResource MyButtonTemplate}"
local:MyButtonThing.Text2="Where's Waldo">
Hello World
</Button>
The attached property route was certainly the way to go to solve this issue. A new subject for me and the examples did not work for me. The control template was not able to recognize the new property.
The change that worked was the way to modify how the attached property is defined.
Thanks to this article for the pointer:
http://www.deepcode.co.uk/2008/08/exposing-new-properties-for-control_15.html
public class MyButtonThing : DependencyObject
{
public static readonly DependencyProperty SubTextProperty =
DependencyProperty.RegisterAttached("SubText",
typeof(String), typeof(MyButtonThing),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsArrange));
public static void SetSubText(UIElement element, object o)
{
element.SetValue(SubTextProperty, o);
}
public static string GetSubText(UIElement element)
{
return (string)element.GetValue(SubTextProperty);
}
}

How do I get WPF searchbox styling like GoogleChrome browser search?

I am planning to have search functionality in WPF like it happens in Google Chrome browser. The sample is shown below
I have the backend code ready, but I want to have a TextBox like the one shown below - in which I can display the results also(like 0 of 0).
Also I would like to have the arrow marks for next and prev.
How do I design such a TextBox in WPF in XAML? Please guide me regarding the same.
A custom control can be created using following code:
public class SearchTextBox : Control
{
public String Text
{
get { return (String)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(String), typeof(SearchTextBox), new UIPropertyMetadata(null));
public String SearchStatusText
{
get { return (String)GetValue(SearchStatusTextProperty); }
set { SetValue(SearchStatusTextProperty, value); }
}
// Using a DependencyProperty as the backing store for SearchStatusText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SearchStatusTextProperty =
DependencyProperty.Register("SearchStatusText", typeof(String), typeof(SearchTextBox), new UIPropertyMetadata(null));
static SearchTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SearchTextBox), new FrameworkPropertyMetadata(typeof(SearchTextBox)));
}
}
Style in Generic.xaml
<Style TargetType="{x:Type local:SearchTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SearchTextBox}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0"
Text="{TemplateBinding Text}" />
<TextBlock Grid.Column="1"
Text="{TemplateBinding SearchStatusText}"></TextBlock>
<Button Grid.Column="2">
<Polyline Points="0,10 5,0 10,10"
Stroke="Black"
StrokeThickness="2" />
</Button>
<Button Grid.Column="3">
<Polyline Points="0,0 5,10 10,0"
Stroke="Black"
StrokeThickness="2" />
</Button>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You will need to change it according to your needs. But this should be a good starting point.
There is no Ready made solution for your requirement.You have to fiddle quite a few with the controltemplates of existing controls or you can build a custom control from scratch.
http://msdn.microsoft.com/en-us/library/aa970773%28VS.85%29.aspx

Resources