Add second image to content of button - wpf

This is the peace of code for the button:
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border" CornerRadius="8">
<Border.Background>
SlateBlue
</Border.Background>
<StackPanel Orientation="Horizontal" Margin="3">
<Image Source="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}" Height="30" Width="30" Stretch="Fill" Margin="0 0 0 0" />
<TextBlock Text="{Binding Path=Content,RelativeSource={RelativeSource TemplatedParent}}" FontSize="12" VerticalAlignment="Center" Padding="10,0,10,0" />
</StackPanel>
</Border>
</ControlTemplate>
</Button.Template>
As you can see, my button has an image and a text. However, I want to add another image after the text. How do I do this? I already use the Tag property once.
Here's how I use the button:
<myProject:ButtonWithTwoImages x:Name="btnHome" Tag="/Resources/Home.png" Content="Home" Command="{Binding Path=NavigateToCategoriesCommand}" Margin="20 0 0 0"/>
How do I add another image to the button?

I created a new user control called ButtonWithTwoImages, here is the code.
Xaml
<UserControl x:Class="WpfUserControl.ButtonWithTwoImages"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Border x:Name="border" CornerRadius="8">
<Border.Background>
SlateBlue
</Border.Background>
<StackPanel Orientation="Horizontal" Margin="3">
<Image Source="{Binding Path=Image1, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Height="30" Width="30" Stretch="Fill" Margin="0 0 0 0" />
<TextBlock Text="{Binding Path=Content,RelativeSource={RelativeSource TemplatedParent}}" FontSize="12" VerticalAlignment="Center" Padding="10,0,10,0" />
<Image Source="{Binding Path=Image2, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Height="30" Width="30" Stretch="Fill" Margin="0 0 0 0" />
</StackPanel>
</Border>
</UserControl>
Xaml.cs
public partial class ButtonWithTwoImages : UserControl
{
public ButtonWithTwoImages()
{
InitializeComponent();
}
public ImageSource Image1
{
get { return (ImageSource)GetValue(Image1Property); }
set { SetValue(Image1Property, value); }
}
public static readonly DependencyProperty Image1Property = DependencyProperty.Register("Image1", typeof(ImageSource), typeof(ButtonWithTwoImages), new PropertyMetadata(null));
public ImageSource Image2
{
get { return (ImageSource)GetValue(Image2Property); }
set { SetValue(Image2Property, value); }
}
public static readonly DependencyProperty Image2Property = DependencyProperty.Register("Image2", typeof(ImageSource), typeof(ButtonWithTwoImages), new PropertyMetadata(null));
}
How To Use It
<Window x:Class="WpfUserControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mylib="clr-namespace:WpfUserControl">
<Grid>
<mylib:ButtonWithTwoImages Image1="Images\A.jpg" Image2="Images\B.jpg"></mylib:ButtonWithTwoImages>
</Grid>
</Window>

Related

Button event is not triggered from Listbox item template wpf

Here is my xaml
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Blue"
BorderThickness="1"
HorizontalAlignment="Stretch">
<StackPanel HorizontalAlignment="Stretch"
Orientation="Horizontal">
<TextBlock Margin="5"
Text="{Binding Text}" />
<Button Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"
Click="Remove">
<Button.Content>
<Image Source="{Binding DeleteIcon}"
Stretch="Fill"
Height="15"
Width="20" />
</Button.Content>
</Button>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
button event is not triggered in code behind or in viewmodel with command binding. How to fix this?
Trying this... It's work for me....
<ListBox Name="lstNumbers">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Blue"
BorderThickness="1"
HorizontalAlignment="Stretch">
<StackPanel HorizontalAlignment="Stretch"
Orientation="Horizontal">
<TextBlock Margin="5"
Text="{Binding Text}" />
<Button Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"
Click="Remove">
<Button.Content>
<Image Source="{Binding DeleteIcon}"
Stretch="Fill"
Height="15"
Width="20" />
</Button.Content>
</Button>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Cs Code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<Numbers> list = new List<Numbers>();
list.Add(new Numbers() { Text ="1"});
list.Add(new Numbers() { Text = "2" });
lstNumbers.ItemsSource = list;
}
private void Remove(object sender, RoutedEventArgs e)
{
}
public class Numbers
{
public string Text { get; set; }
}

WPF Dependency Property Bound To User Control

I have a button subclass called MenuButton.
public class MenuButton : Button
{
public string Caption
{
get { return (string)GetValue(CaptionProperty); }
set { SetValue(CaptionProperty, value); }
}
public static readonly DependencyProperty CaptionProperty =
DependencyProperty.Register("Caption", typeof(string), typeof(MenuButton), new UIPropertyMetadata(null));
public UserControl Icon
{
get { return (UserControl)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(UserControl), typeof(MenuButton),
new PropertyMetadata(null));
}
In the style I want to show an icon that was created using paths from SVG files. I have created a User Control containing the XAML for the icon:
<UserControl x:Class="WpfApplication1.Views.ScopeIcon"
.
.
.
>
<Viewbox Height="55"
Width="55">
<Grid>
<Path Fill="LightBlue" Data="M98.219,48.111C97..."/>
<Path Fill="LightBlue" Data="M98.219,46.948C97...."/>
</Grid>
</Viewbox>
</UserControl>
And here's the style:
<Style TargetType="Button"
x:Key="TestButtonStyle">
<Setter Property="Height" Value="140"/>
<Setter Property="Width" Value="195"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:MenuButton}">
<Border x:Name="TheBorder">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50*"/>
<RowDefinition Height="50*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Row="0"/> <===== THE USER CONTROL WILL GO HERE
<TextBlock Grid.Row="1"
Grid.Column="0"
Text="{TemplateBinding Caption}"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="5"
Foreground="White"
FontSize="14"
TextAlignment="Center"
TextWrapping="WrapWithOverflow"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I will set it here:
<ListBox Grid.Row="0"
ItemsSource="{Binding MainTools}" >
<ListBox.ItemTemplate>
<DataTemplate>
<controls:MenuButton Caption="{Binding Caption}"
Margin="2"
Width="100"
Style="{StaticResource TestButtonStyle}"
VerticalAlignment="Top"
Command="{Binding Path=ButtonClick}"
CommandParameter="{x:Static enums:Tabs.Oscilloscope}"
Icon=""/> <============= HOW DO I PUT THE SCOPEICON USER CONTROL HERE?
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm essentially trying to nest user controls, but I want to tell the button, in XAML, what UserControl to use for its icon.
Thank you
First, you need to update your style to set Content property on your ContentPresenter the same way you did for Text property on TextBlock.
<ContentPresenter Grid.Row="0" Content="{TemplateBinding Icon}"/>
And, then to set Icon on the MenuButton in your DataTemplate update your MenuButton element in DataTemplate to something like:
<controls:MenuButton Caption="Caption"
Margin="2"
Width="100"
Style="{StaticResource TestButtonStyle}"
VerticalAlignment="Top"
Command="{Binding Path=ButtonClick}"
CommandParameter="{x:Static enums:Tabs.Oscilloscope}">
<controls:MenuButton.Icon>
<views:ScopeIcon />
</controls:MenuButton.Icon>
</controls:MenuButton>

Configurable HeaderTemplate

I have about 12 Expanders that need to have a custom HeaderTemplate. The HeaderTemplate has a textblock to display the header text, along with a button. The button has a custom control template so that I can display the button as a Path within a VisualBrush.
<Expander VerticalAlignment="Top"
Header="Fields"
IsExpanded="True">
<Expander.HeaderTemplate>
<DataTemplate>
<DockPanel LastChildFill="False">
<TextBlock VerticalAlignment="Center"
DockPanel.Dock="Left"
FontSize="14"
Foreground="{DynamicResource IdealForegroundColorBrush}"
Text="{Binding}"/>
<Button DockPanel.Dock="Right" Margin="0 0 10 0"
Command="{Binding RelativeSource={RelativeSource AncestorType=Expander}, Path=DataContext.AddFieldCommand}">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<Rectangle Fill="Transparent" />
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Content="{TemplateBinding Content}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Grid>
</ControlTemplate>
</Button.Template>
<Rectangle Width="20" Height="20" Fill="{DynamicResource EditIconBrush}" />
</Button>
</DockPanel>
</DataTemplate>
</Expander.HeaderTemplate>
I would like to re-use this template across all 12 Expanders, but need to specify what icon and Command the button within the template will use. How would I go about doing that? Can this be achieved by breaking the data template up in to a series of templates? What I want to do is move the template into a static resource
<Expander VerticalAlignment="Top"
Header="Fields"
IsExpanded="True"
HeaderTemplate="{StaticResource IconHeader}">
I'm just not sure how to provide the template what Command and Icon resource it should use. Would a Dependency property make sense here?
Thanks.
I believe that there are at least to ways to achieve this. First is to inherit from Expander, extend it with your Dependency properties and bind to them inside DataTemplate.
Another way to do this is to create some attached properties, and bind to them inside DataTemplate as below:
public class TemplateConfig
{
public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof (ICommand), typeof (TemplateConfig), new PropertyMetadata(default(ICommand)));
public static void SetCommand(DependencyObject element, ICommand value)
{
element.SetValue(CommandProperty, value);
}
public static ICommand GetCommand(DependencyObject element)
{
return (ICommand) element.GetValue(CommandProperty);
}
public static readonly DependencyProperty IconProperty = DependencyProperty.RegisterAttached("Icon", typeof (VisualBrush), typeof (TemplateConfig), new PropertyMetadata(default(VisualBrush)));
public static void SetIcon(DependencyObject element, VisualBrush value)
{
element.SetValue(IconProperty, value);
}
public static VisualBrush GetIcon(DependencyObject element)
{
return (VisualBrush) element.GetValue(IconProperty);
}
}
Header template:
<DataTemplate x:Key="ExpanderHeaderTemplate">
<DockPanel LastChildFill="False">
<TextBlock VerticalAlignment="Center"
DockPanel.Dock="Left"
FontSize="14"
Text="{Binding}" />
<Button Margin="0 0 10 0"
Command="{Binding Path=(test:TemplateConfig.Command),
RelativeSource={RelativeSource AncestorType=Expander}}"
DockPanel.Dock="Right">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<Rectangle Fill="Transparent" />
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Button.Template>
<Rectangle Width="20"
Height="20"
Fill="{Binding Path=(test:TemplateConfig.Icon),
RelativeSource={RelativeSource AncestorType=Expander}}" />
</Button>
</DockPanel>
</DataTemplate>
and finally expander:
<Expander VerticalAlignment="Top"
Header="Fields"
HeaderTemplate="{StaticResource ExpanderHeaderTemplate}"
IsExpanded="True"
test:TemplateConfig.Command="{Binding SomeCommand}"
test:TemplateConfig.Icon="{StaticResource VisualBrush}" />
Hope this helps.

How to use WrapPanel's DataTemplate

I've a WrapPanel to show some elements. But I want to use DataTemplate to show them.
Here is my XAML code of WrapPanel
<WrapPanel Margin="10,57,12,10" x:Name="wrp1">
<WrapPanel.Resources>
<DataTemplate DataType="{x:Type local:DateItem}">
<Grid VerticalAlignment="Top" HorizontalAlignment="Stretch" Width="250" Height="300" Background="Blue">
<Label Content="{Binding Path=DateString}" FontSize="20" Cursor="Hand" Foreground="White" Background="Red" FontWeight="Bold" VerticalAlignment="Bottom" HorizontalAlignment="Left" Height="38" VerticalContentAlignment="Center" Padding="5,0,5,0"/>
</Grid>
</DataTemplate>
</WrapPanel.Resources>
</WrapPanel>
And this is the code of DateItem
public class DateItem : UIElement
{
public string DateString { get; set; }
}
When the window initialized, i'm creating one DateItem with DateString parameter and adding that to WrapPanel as child.
DateItem di = new DateItem();
di.DateString = "28.04.2014";
wrp1.Children.Add(di);
I think everything is fine but wrap panel shows nothing :(
Can you help me with this?
You have confused UI controls with DataTemplates which is used to define the presentation of your data. To render data, you have to set content of control which can be done using ContentControl.
Also, you can use ItemsControl if you want to add multiple times.
XAML:
<WrapPanel x:Name="wrp1">
<WrapPanel.Resources>
<DataTemplate DataType="{x:Type local:DateItem}">
<Grid VerticalAlignment="Top" HorizontalAlignment="Stretch" Width="250"
Height="300" Background="Blue">
<Label Content="{Binding Path=DateString}" FontSize="20" Cursor="Hand"
Foreground="White" Background="Red" FontWeight="Bold"
VerticalAlignment="Bottom" HorizontalAlignment="Left"
Height="38" VerticalContentAlignment="Center"
Padding="5,0,5,0"/>
</Grid>
</DataTemplate>
</WrapPanel.Resources>
<ItemsControl x:Name="itemsControl"/>
</WrapPanel>
Code behind:
DateItem di = new DateItem();
di.DateString = "28.04.2014";
itemsControl.Items.Add(di);
DateItem:
public class DateItem
{
public string DateString { get; set; }
}
In case you still interested in rendering it as a Control, you have to define default Style and not default template.
XAML:
<WrapPanel x:Name="wrp1">
<WrapPanel.Resources>
<Style TargetType="{x:Type local:DateItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid VerticalAlignment="Top" HorizontalAlignment="Stretch"
Width="250" Height="300" Background="Blue">
<Label
Content="{Binding Path=DateString, RelativeSource=
{RelativeSource Mode=TemplatedParent}}"
FontSize="20" Cursor="Hand" Foreground="White"
Background="Red" FontWeight="Bold"
VerticalAlignment="Bottom"
HorizontalAlignment="Left"
Height="38" VerticalContentAlignment="Center"
Padding="5,0,5,0"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</WrapPanel.Resources>
</WrapPanel>
Code behind:
DateItem di = new DateItem();
di.DateString = "28.04.2014";
wrp1.Children.Add(di);
DateItem:
public class DateItem : Control
{
public string DateString { get; set; }
}

Closing Caliburn Micro View from a UserControl Button?

I have created a UserControl name TitleBar, which is placed in every view.
The TitleBar.xaml contains a Button to close the Window in which it contain.
How can i close a Caliburn Window using that Button.
TitleBar UserControl
<UserControl x:Class="JIMS.Controls.TitleBar"
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">
<Grid Style="{StaticResource TitleBar}">
<Rectangle HorizontalAlignment="Stretch" Height="7" Margin="0,0,-5,0" VerticalAlignment="Top" Fill="{DynamicResource DefaultBrush}"></Rectangle>
<Grid HorizontalAlignment="Left" Margin="-10,-5,0,0" Name="Logo">
<TextBlock Name="txtTitle" Style="{StaticResource Title}">JIMS</TextBlock>
<Ellipse HorizontalAlignment="Right" Margin="0,0,5,0" Width="20" Height="20">
<Ellipse.Fill>
<VisualBrush Stretch="Fill" Visual="{StaticResource appbar_settings_white}" />
</Ellipse.Fill>
</Ellipse>
</Grid>
<Grid HorizontalAlignment="Right">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,5,-4,0">
<Button Name="btnClose" Style="{StaticResource ChromeButtonStyle}" Click="btnClose_Click" IsTabStop="False">
<TextBlock TextWrapping="Wrap" Text="r" FontFamily="Webdings" Foreground="#FF919191" FontSize="13.333" />
</Button>
</StackPanel>
</Grid>
</Grid>
</UserControl>
TitleBar Usage in a View
<UserControl xmlns:my="clr-namespace:JIMS.Controls;assembly=JIMS.Controls" x:Class="JIMS.Views.Stock.UnitView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="Unit">
<Border Style="{StaticResource WindowBorderStyle}">
<StackPanel Orientation="Vertical">
<my:TitleBar Title="unit creation"/>
<StackPanel Visibility="{Binding ControlVisiblity}" Orientation="Horizontal" Margin="0,5,0,5">
<StackPanel Orientation="Vertical" Margin="10,0,0,0">
<Label>Short Name :</Label>
<Label>Unit Name :</Label>
</StackPanel>
<StackPanel Orientation="Vertical" Width="200" Margin="0,0,10,0">
<TextBox Name="txtShortName" Text="{Binding Path=UnitShort}"></TextBox>
<TextBox Name="txtUnitName" Text="{Binding Path=UnitName}"></TextBox>
</StackPanel>
</StackPanel>
<Expander Style="{StaticResource DisplayExpander}" IsExpanded="{Binding IsDisplayExpanded}" Header="display units">
<StackPanel Orientation="Horizontal" Margin="0,5,0,5" Visibility="{Binding DisplayVisiblity}">
<DataGrid AutoGenerateColumns="True" Height="200" MinWidth="300" ItemsSource="{Binding Display}"></DataGrid>
</StackPanel>
</Expander>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Name="SaveUnit" Style="{StaticResource MetroButton}">Save</Button>
</StackPanel>
</StackPanel>
</Border>
</UserControl>
In your TitleBar control define a RoutedEvent like this
public event RoutedEventHandler CloseClick
{
add { AddHandler(CloseClickEvent, value); }
remove { RemoveHandler(CloseClickEvent, value); }
}
public static readonly RoutedEvent CloseClickEvent = EventManager.RegisterRoutedEvent(
"CloseClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TitleBar));
void RaiseCloseClickEvent()
{
var newEventArgs = new RoutedEventArgs(TitleBar.CloseClickEvent);
RaiseEvent(newEventArgs);
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
RaiseCloseClickEvent();
}
And attach the btnClose_Click event handler to the btnClose control in your TitleBar
Now, when you use your TitleBar add an action like this
<my:TitleBar Title="This is the title">
<i:Interaction.Triggers>
<i:EventTrigger EventName="CloseClick">
<cal:ActionMessage MethodName="Close"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</my:TitleBar>
This will call the method Close on your viewmodel when the the CloseClickEvent is raised on the TitleBar.
For closing the window, you could derive your viewmodel from Screen and add the following snippet
public void Close()
{
TryClose();
}

Resources