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

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>

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 >

How to get image source in Control Template

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.

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

TemplateBinding doesn't bind to effect's property?

Imagine a control named Testko like this:
public class Testko: Control
{
public static readonly DependencyProperty TestValueProperty;
static Testko()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Testko), new FrameworkPropertyMetadata(typeof(Testko)));
TestValueProperty = DependencyProperty.Register("TestValue", typeof(double), typeof(Testko), new UIPropertyMetadata((double)1));
}
public double TestValue
{
get { return (double)GetValue(TestValueProperty); }
set { SetValue(TestValueProperty, value); }
}
}
Nothing fancy, just an empty control with a single double property with a default value set to (double)1.
Now, image a generic style like this:
<Style TargetType="{x:Type local:Testko}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Testko}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel Orientation="Vertical">
<StackPanel.Effect>
<BlurEffect Radius="{TemplateBinding TestValue}" />
</StackPanel.Effect>
<Button Content="{TemplateBinding TestValue}" Margin="4" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now, the problem is that Radius property is never bound for some reason. Wheras Button's content is properly bound to TestValue property.
I am sure I am missing something obvious. Or not?
If it is obvious, it is not to me :-)
My favorite book (WPF Unleashed) mentions that sometimes TemplatedBinding doesn't work (but the enumerated reasons don't match your circumstances).
But TemplatedBinding is a shortcut for:
{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TestValue}
I reproduced your case, i.e. changing TestValue only has effect on the button.
After replacing the TemplatedBinding by this, I get the desired effect.

Resources