How to create a Grid style with element existed inside in WPF - wpf

I'm quite new in WPF. My problem is I want to create a Grid with text in background. Below is my code.
But I want to create a style to reuse in many windows.
How can I create it in ResourceDictionary?
<Grid>
<ListBox Opacity="0.5" Width="100" Height="100"></ListBox>
<TextBlock Text="My text" Foreground="Black" Opacity="0.5" FontSize="50" FontWeight="Bold">
<TextBlock.LayoutTransform>
<RotateTransform Angle="-45"></RotateTransform>
</TextBlock.LayoutTransform>
</TextBlock>
<Grid.Background>
<SolidColorBrush Color="LightPink" Opacity="0.5"/>
</Grid.Background>
</Grid>
I tried to code some line:
<Style x:Key="myGridStyle" TargetType="{x:Type Grid}">
<Setter Property="Background" Value="LightPink"/>
<Setter Property="Opacity" Value="0.5"/>
<!--what i have to code here?-->
</Style>
Please help me to continue.
Thank you in advanced!

Create a UserControl with that XAML and add Dependency Property to it.
Example :
Create a UserControl and add following code in your .cs file
...
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(nameof(Text), typeof(string), typeof(UserControl1), new PropertyMetadata(string.Empty));
public UserControl1()
{
InitializeComponent();
}
...
then add this XAML code to your UserConstrol
<Grid>
<ListBox Opacity="0.5" Width="100" Height="100"></ListBox>
<TextBlock Text="{Binding Text, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" Foreground="Black" Opacity="0.5" FontSize="50" FontWeight="Bold">
<TextBlock.LayoutTransform>
<RotateTransform Angle="-45"></RotateTransform>
</TextBlock.LayoutTransform>
</TextBlock>
<Grid.Background>
<SolidColorBrush Color="LightPink" Opacity="0.5"/>
</Grid.Background>
</Grid>
and finally test it
<local:UserControl1 Text="something" />

Related

how to bind collection to custom control in wpf

I am building a custom control and I want to pass a collection to it so that control display that collection, my code is as the following :
<gm:Calendar SubscriptionSource="{Binding Subscriptions}"></gm:Calendar>
and in Custom control "Calendar"
public static readonly DependencyProperty SubscriptionSourceProperty =
DependencyProperty.Register(
"SubscriptionSource",
typeof(ObservableCollection<Subscription>),
typeof(Calendar),
new FrameworkPropertyMetadata(new ObservableCollection<Subscription>()));
public ObservableCollection<Subscription> SubscriptionSource
{
get
{
return (ObservableCollection<Subscription>)GetValue(SubscriptionSourceProperty);
}
set
{
SetValue(SubscriptionSourceProperty, value);
}
}
I use in generic.xaml
<ItemsControl ItemsSource="{Binding SubscriptionSource}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Box-->
<Border BorderBrush="Black" BorderThickness="1" Padding="0">
<Border Name="InnerBorder" BorderBrush="{Binding Path=Day, Converter={StaticResource DayBorderColorConverter}}" BorderThickness="2">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<!--Current Day-->
<DataTrigger Binding="{Binding IsToday}" Value="true">
<Setter Property="Border.Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF1EA6C8" Offset="0"/>
<GradientStop Color="#FF0691B3" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<DockPanel>
<!--Day Number-->
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" FlowDirection="RightToLeft">
<TextBlock TextAlignment="Right" Text="{Binding Day.Date, Converter={StaticResource DateConverter}, ConverterParameter=DAY}" FontSize="12" Margin="5,5,5,5" >
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsTargetMonth}" Value="false">
<Setter Property="TextBlock.Foreground" Value="Gray"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
<CheckBox IsEnabled="{Binding IsEnabled}" Style="{StaticResource DiscreteCheckBoxStyle}" />
</DockPanel>
</Border>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="6" Columns="7" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
I want to Bind Subscriptions observable collection to the calendar custom control so I can use the collection in the custom control, is there is away to do this?
If the ItemsControl is inside the ControlTemplate, then Change the {Binding SubscriptionSource} for {TemplateBinding SubscriptionSource}
My problem is now Solved thanks to #Luke Woodward and I just had another problem that I use the custom control inside usercontrol and that usercontrol was an item inside ListItem
I modified the binding expression
<gm:Calendar SubscriptionSource="{Binding Path=Subscriptions,Mode=TwoWay}" >
and the customcontrol is
static Calendar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Calendar), new FrameworkPropertyMetadata(typeof(Calendar)));
}
public ObservableCollection<SubscriptionDay> SubscriptionSource
{
get { return (ObservableCollection<SubscriptionDay>)GetValue(SubscriptionSourceProperty); }
set { SetValue(SubscriptionSourceProperty, value); }
}
public static readonly DependencyProperty SubscriptionSourceProperty =
DependencyProperty.Register("SubscriptionSource", typeof(ObservableCollection<SubscriptionDay>), typeof(Calendar), new FrameworkPropertyMetadata(new ObservableCollection<SubscriptionDay>()));
and in the Generic.xaml modified as #HighCore posted
<ItemsControl ItemsSource="{TemplateBinding SubscriptionSource}">
<ItemsControl.ItemTemplate>
<DataTemplate>......
and finally worked.
Thanks to #Luke Woodward and #HighCore

Trying to pass validation to my custom tooltip control

I am trying to make a custom tooltip control that is used for TextBoxes.
It will look like this:
...except for some pixels that comes from the background components that I have gimped away as good as possible.
The idea comes from:
How to implement Balloon message in a WPF application
The problem is that the code behind of my custom control never gets the validation object (that should be passed to it via the trigger in generic.xaml).
Why not?
generic.xaml:
<Style TargetType="{x:Type TextBox}" x:Name="tb">
<Setter Property="Width" Value="200" />
<Setter Property="Background" Value="{StaticResource InputBackgroundColor}" />
<Setter Property="BorderBrush" Value="{StaticResource InputBorderBrush}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Margin" Value="5,0,0,5" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip">
<Setter.Value>
<Windows:ValidationBalloonPopupWindow
Validation="{Binding Path=Validation, ElementName=tb}" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
As you see, I try to refer to Validation by using ElementName of tb.
Seems like Name is not used in templates. If I change to x:Key instead, all my textboxes becomes like 10 pixels wide. Probably not the right thing to do in other words.
The code behind, ValidationBalloonPopupWindow.xaml.cs:
using System.Windows;
using System.Windows.Controls;
namespace Foo.ToolTips
{
public partial class ValidationBalloonPopupWindow : ToolTip
{
public ValidationBalloonPopupWindow()
{
InitializeComponent();
}
public static DependencyProperty ValidationProperty
= DependencyProperty.Register("Validation", typeof(object), typeof(ValidationBalloonPopupWindow),
new PropertyMetadata(null, OnChangedValidationByBinding));
private static void OnChangedValidationByBinding
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ValidationBalloonPopupWindow)d).OnChangedValidationByBinding(e.NewValue);
}
public void OnChangedValidationByBinding(object newValue)
{
txtMessage.Text = newValue.GetType().Name;
}
private object _validation;
public object Validation
{
get
{
return _validation;
}
set
{
_validation = value;
txtMessage.Text = _validation.GetType().Name;
}
}
}
}
Which has a setter that should run, I have tried to put a lot of breakpoints in this file without success.
The xaml for the control itself, ValidationBalloonPopupWindow.xaml:
<ToolTip x:Class="FRAM.Windows.ValidationBalloonPopupWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent" BorderBrush="Transparent" HasDropShadow="false"
Placement="Bottom"
Height="Auto" Width="Auto">
<Grid Height="126" Width="453">
<Border Margin="7,13,0,0"
CornerRadius="10,10,10,10" Grid.ColumnSpan="4" HorizontalAlignment="Left" Width="429" Height="82" VerticalAlignment="Top" Grid.RowSpan="2">
<Border.Effect>
<DropShadowEffect Color="#FF474747" />
</Border.Effect>
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF58C2FF" Offset="0" />
<GradientStop Color="#FFFFFFFF" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel Orientation="Vertical">
<Label Content="Title" Height="31" HorizontalAlignment="Left"
Margin="12,8,0,0" Name="lblCaption" FontSize="16" FontWeight="Bold" />
<TextBlock Margin="18,0,0,0" Name="txtMessage" Width="378" HorizontalAlignment="Left">Body</TextBlock>
</StackPanel>
</Border>
<Path Data="M25,25L10.9919,0.64 0.7,25" Fill="#FF58C2FF" HorizontalAlignment="Left"
Margin="32,3,0,0" Stretch="Fill" Width="22" Height="10" VerticalAlignment="Top" />
</Grid>
</ToolTip>
Instead of referring by name, get the Textbox itself by using RelativeSource binding.
Try something like this:
<Setter Property="ToolTip">
<Setter.Value>
<Windows:ValidationBalloonPopupWindow
Validation="{Binding RelativeSource={RelativeSource Self}, Path=Validation}" />
</Setter.Value>
</Setter>

ListBox with embedded CheckBox restricting one item to be checked

I have a ListBox containing an ItemTemplate made up of a StackPanel containing a CheckBox and a Label. I want to allow only one list item to be checked at a time. I am having trouble understanding how I can get this accomplished. Here is the XAML describing the listbox:
<ListBox Grid.Row="0"
Grid.Column="0"
Width="180"
HorizontalAlignment="Left"
x:Name="listboxPlayers"
ItemsSource="{Binding Players}"
SelectedItem="{Binding SelectedPlayer, Mode=TwoWay}"
ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsDefault, Mode=TwoWay}"
VerticalAlignment="Center"
Checked="CheckBox_Checked"
Unchecked="CheckBox_Unchecked"/>
<Label Content="{Binding Name}"
VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
A Player is defined as this:
public class Player
{
public string Name { get; set; }
public bool IsDefault { get; set; }
}
My list of Players is defined like this:
public ObservableCollection<Player> Players { get; private set; }
My SelectedPlayer is defined like this:
public static readonly DependencyProperty SelectedPlayerProperty =
DependencyProperty.Register("SelectedPlayer", typeof(Player), typeof(MainWindow),
new FrameworkPropertyMetadata());
public Player SelectedPlayer
{
get { return (Player)GetValue(SelectedPlayerProperty); }
set { SetValue(SelectedPlayerProperty, value); }
}
I haven't been able to find a post or question that can help me. I've played with using a Checked event handler for the CheckBox but I can't seem to wrap my head around how I can relate the list to the correct Player in the list because the ListBox doesn't adjust the SelectedPlayer when the CheckBox is checked or unchecked.
Thanks very much.
I usually use the following style for displaying a ListBox using CheckBoxes (You can use RadioButtons too by just replacing the CheckBox control with a RadioButton
<Style x:Key="CheckBoxListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="KeyboardNavigation.DirectionalNavigation" Value="Cycle" />
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}" >
<Setter Property="Margin" Value="2, 2, 2, 0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Background="Transparent">
<CheckBox IsHitTestVisible="False" Focusable="false"
Content="{TemplateBinding ContentPresenter.Content}"
IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
Then it is simply used by something like
<ListBox ItemsSource="{Binding Players}"
Style="{StaticResource CheckBoxListBoxStyle}"
SelectedItem="{Binding SelectedPlayer, Mode=TwoWay}">
If you have something that should behave like a RadioButton, why not use a RadioButton?
Try configuring your ListBox to Selection Mode Single. And rather than a separate label you could just bind Name to the Content property of the CheckBox. I like the way that spaces. And you may need to implement InotifyPropertyChanged on player.

How to assign the source of an image in a style wrapping ListBoxItem

In the following code, there is a style for ListBoxItem, with a textblock and an Image.
The textblock has a binding to the ListBoxItem content, and the Image is set in the style.
I want to be able to set this image for each listboxitem and in code, I'm wondering if
someone can get me on the right track.
Thanks for any help.
code snippet of the style and using it:
<Style x:Key="ExpanderListitemStyle" TargetType="{x:Type ListBoxItem}">
<StackPanel Orientation="Horizontal">
<Image x:Name="iGalleryPreview" Source="images/someImage.png" Width="18" Height="18"/>
<TextBlock x:Name="con" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Text="{TemplateBinding Content}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Margin="5,0,0,0">
<TextBlock.Foreground>
<SolidColorBrush Color="#FF2A485C" x:Name="contentColor" />
</TextBlock.Foreground>
</TextBlock>
</StackPanel>
<ListBox BorderThickness="0" ItemContainerStyle="{DynamicResource ExpanderListitemStyle}" VerticalAlignment="Stretch" Height="Auto">
<ListBoxItem Content="Some Label" />
<ListBoxItem Content="Another Label"/>
</ListBox>
Let's assume we have an Employee class, we store for each employee her name and image as follows:
public class Employee
{
public string Image { get; set; }
public string Name { get; set; }
}
Instead of a Style you need to use an ItemTemplate as follows:
<Window x:Class="ProofOfConcept.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox ItemsSource="{Binding}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="TextBlock.Foreground"
Value="Green"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="TextBlock.Foreground"
Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Image Stretch="UniformToFill" Height="24"
Width="24" Margin="2,1"
Source="{Binding Image}"/>
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
your code behind will be something like this:
using System.Windows;
namespace ProofOfConcept
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var emps =
new Employee[]
{
new Employee {Image = "/Images/1.png", Name = "Mohamed A. Fadil"},
new Employee {Image = "/Images/6.png", Name = "Sara Konor :)"},
new Employee {Image = "/Images/2.png", Name = "John M. Arther"},
new Employee {Image = "/Images/3.png", Name = "Khalid El-Sheikh"},
new Employee {Image = "/Images/4.png", Name = "Hassan A. Fadil"},
new Employee {Image = "/Images/5.png", Name = "Criss Redfield"}
};
DataContext = emps;
}
}
}
And finally the result :D

how to change button template dynamically WPF

How can I change a Button template dynamically?
I have a ComboBox where by changing his selected value I want to change a Button Template.
This is what I have been trying to do:
<Window.Resources>
<ControlTemplate x:Key="ButtonControlTemplate1" TargetType="{x:Type Button}">
<Grid>
<Rectangle Fill="#FF2D2D7A" Margin="7.5,9.5,8.5,11" Stroke="Black"
RadiusX="45" RadiusY="45" StrokeThickness="6"/>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="ButtonControlTemplate2" TargetType="{x:Type Button}">
<Grid>
<ed:RegularPolygon Fill="#FFE7F9C9" Height="Auto" InnerRadius="0.47211"
Margin="20.5,16,15.5,8" PointCount="5" Stretch="Fill"
Stroke="Black" StrokeThickness="6" Width="Auto"/>
</Grid>
</ControlTemplate>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<ComboBox Name="GroupBoxHeaderComboBox" ItemsSource="{Binding Path=collection}"
DisplayMemberPath="Key" Height="52" Margin="211.5,60,230.5,0"
VerticalAlignment="Top" SelectedIndex="1"/>
<Button Content="Button" HorizontalAlignment="Left" Height="102" Margin="47.5,0,0,91"
VerticalAlignment="Bottom" Width="132"
Template="{DynamicResource ButtonControlTemplate2}"/>
<Button Content="Button" HorizontalAlignment="Right" Height="112.5" Margin="0,0,27.5,85"
VerticalAlignment="Bottom" Width="153"
Template="{DynamicResource ButtonControlTemplate1}"/>
<Button Content="Button" Height="102" Margin="239.5,0,252.5,13.5"
VerticalAlignment="Bottom"
Template="{Binding ElementName=GroupBoxHeaderComboBox, Path=SelectedItem.Value}"/>
</Grid>
And here are the associated Templates:
<Window.Resources>
<ControlTemplate x:Key="ButtonControlTemplate1" TargetType="{x:Type Button}">
<Grid>
<Rectangle Fill="#FF2D2D7A" Margin="7.5,9.5,8.5,11" Stroke="Black"
RadiusX="45" RadiusY="45" StrokeThickness="6"/>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="ButtonControlTemplate2" TargetType="{x:Type Button}">
<Grid>
<ed:RegularPolygon Fill="#FFE7F9C9" Height="Auto" InnerRadius="0.47211"
Margin="20.5,16,15.5,8" PointCount="5" Stretch="Fill"
Stroke="Black" StrokeThickness="6" Width="Auto"/>
</Grid>
</ControlTemplate>
</Window.Resources>
And the code behind:
public partial class MainWindow : Window
{
public Dictionary<string, string> collection
{
get;
private set;
}
public MainWindow()
{
this.InitializeComponent();
DataContext = this;
collection = new Dictionary<string, string>()
{
{ "DynamicResource ButtonControlTemplate2", "{DynamicResource ButtonControlTemplate2}"},
{ "DynamicResource ButtonControlTemplate1", "{DynamicResource ButtonControlTemplate2}"},
};
// Insert code required on object creation below this point.
}
}
Is there another genric way to acomplish this?... I want that most of the code would be xaml.
EDIT:
Is there a point to do it using a style? Let's say I want more then one object to act, otherwise is there a point to change the style and to do it all from there?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public Dictionary<string, ControlTemplate> collection
{
get
{
Dictionary<string, ControlTemplate> controlTemplates = new Dictionary<string, ControlTemplate>();
controlTemplates.Add("ButtonControlTemplate1", FindResource("ButtonControlTemplate1") as ControlTemplate);
controlTemplates.Add("ButtonControlTemplate2", FindResource("ButtonControlTemplate2") as ControlTemplate);
return controlTemplates;
}
}
}
Create a ControlTemplate in Windows resource,
<Window.Resources>
<ControlTemplate x:Key="GreenTemplate" TargetType="{x:Type Button}">
<Grid>
<Ellipse Fill="Green"/>
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Window.Resources>
Now in run time you can change the template property of button.
private void Button_Clicked(object sender, RoutedEventArgs e)
{
Button btn = e.OriginalSource as Button;
if (btn != null)
{
btn.Template = FindResource("GreenTemplate") as ControlTemplate;
}
}
You can use a data trigger and do it all in xaml.
This uses a tree but the concept is the same
<Window x:Class="WpfBindingTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfBindingTest"
Title="Window3" Height="300" Width="300" Name="win3" >
<Window.Resources>
<XmlDataProvider x:Key="treeData" XPath="*">
<x:XData>
<Items Name="Items" xmlns="">
<Item1/>
<Item2>
<Item22/>
<Item12/>
<Item13>
<Item131/>
<Item131/>
</Item13>
</Item2>
</Items>
</x:XData>
</XmlDataProvider>
<HierarchicalDataTemplate ItemsSource="{Binding XPath=child::*}" x:Key="template">
<TextBlock Name="textBlock" Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</Window.Resources>
<StackPanel>
<TreeView ItemTemplate="{StaticResource template}"
Name="treeView"
ItemsSource="{Binding Source={StaticResource treeData}}">
<TreeView.ItemContainerStyle>
<!--Using style setter to set the TreeViewItem.IsExpanded property to true, this will be applied
to all TreeViweItems when they are generated-->
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
<Button Width="120" Height="30">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Content" Value="Default" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=treeView, Path=SelectedItem.Name}" Value="Item12">
<Setter Property="Content" Value="Now changed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
from here.
(I just googled to get an example faster)

Resources