I have a binded ListView like so :
<ListView Margin="0,10,8,-10" BorderThickness="2" BorderBrush="AliceBlue"
ItemsSource="{Binding PackageBrowser.Documents}"
SelectedItem="{Binding SelectedDocument}"
View="{Binding PackageBrowser.ColumnConfig, Converter={Converters:ConfigToDynamicGridViewConverter}}">... </ListView>
The main purpose of this binding is to generate dynamic column.
Here is my Converter:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var config = value as ColumnConfig;
var gridView = new GridView();
var actualColumn = new GridViewColumn() { Header = "Name", DisplayMemberBinding = new Binding("Name") };
gridView.Columns.Add(actualColumn);
if (config != null)
{
foreach (var column in config.Columns)
{
var binding = new Binding(string.Format(CultureInfo.InvariantCulture, "ColumnValues[{0}]", column.Name));
gridView.Columns.Add(new GridViewColumn { Header = column.Header, DisplayMemberBinding = binding });
}
foreach (GridViewColumn c in gridView.Columns)
{
// Code below was found in GridViewColumnHeader.OnGripperDoubleClicked() event handler (using Reflector)
// i.e. it is the same code that is executed when the gripper is double clicked
// if (adjustAllColumns || App.StaticGabeLib.FieldDefsGrid[colNum].DispGrid)
if (double.IsNaN(c.Width))
{
c.Width = c.ActualWidth;
}
c.Width = double.NaN;
}
}
return gridView;
}
My question is :
How can I modify the ColumnHeaderContainerStyle of my gridView so all the column cannot be resize.
Something like that but in the code behind :
<GridView.ColumnHeaderContainerStyle>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="IsEnabled" Value="False"/>
</Style>
</GridView.ColumnHeaderContainerStyle>
I guess, You might be written missing code (ColumnHeaderContainerStyle). If you write any style for ColumnHeaderStyle.You must complete all features(If you want to make different designs).For example : Thumb,ContentPresenter etc.I have written a listview style code for you.
(Sorry,I dont know very well English.I hope this is what you want)
Here is code:
<Style x:Key="GridViewColumnHeaderGripper" TargetType="Thumb">
<Setter Property="Width" Value="18"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Padding="{TemplateBinding Padding}" Background="Transparent">
<Rectangle HorizontalAlignment="Center" Width="1" Fill="#FFD4D4D4"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{x:Type GridViewColumnHeader}" TargetType="GridViewColumnHeader">
<Setter Property="FontFamily" Value="Tahoma"/>
<Setter Property="Foreground" Value="#FF003362"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewColumnHeader">
<Grid>
<Border Background="White" BorderBrush="#FFD4D4D4" BorderThickness="1,1,0,1" Name="HeaderBorder" Padding="{TemplateBinding Padding}">
<ContentPresenter Name="HeaderContent" Content="{TemplateBinding Content}" Margin="0,0,0,1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<Thumb x:Name="PART_HeaderGripper" HorizontalAlignment="Right" Margin="0,0,-9,0" Style="{StaticResource GridViewColumnHeaderGripper}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="HeaderContent" Property="Margin" Value="1,1,0,0"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" Value=".5" TargetName="HeaderBorder"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Role" Value="Floating">
<Setter Property="Opacity" Value="0.7" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewColumnHeader">
<Canvas Name="PART_FloatingHeaderCanvas">
<Rectangle Fill="#60000000" Width="{TemplateBinding ActualWidth}" Height="{TemplateBinding ActualHeight}"/>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Related
I want to implement a button, that have 4 stage (Stage1/Stage2/Stage3/Stage4)
and I want to click on it, the text and style will change (Stage1 -> Stage2 -> Stage3 -> Stage4 -> Stage1 -> ....)
Here is my XAML button code.
<ControlTemplate x:Key="StageButton" TargetType="{x:Type Button}">
<Button
Width="102"
Tag="1"
Click="Hello_Click"
BorderThickness="0"
Background="Transparent"
Cursor="Hand">
<Border
BorderThickness="2"
BorderBrush="Gray"
CornerRadius="10"
Background="Green"
Width="100"
Height="20"
>
<TextBlock
Width="100"
Foreground="White"
FontWeight="Bold"
FontSize="12"
Padding="14 1 0 0"
Text="Stage1"
/>
</Border>
</Button>
</ControlTemplate>
Thanks for help
You can make a custom Button with incremental stage (starting at 1) functionality:
using System;
using System.Windows;
using System.Windows.Controls;
public class StagedButton : Button
{
public int Stage
{
get { return (int)GetValue(StageProperty); }
set { SetValue(StageProperty, value); }
}
public static readonly DependencyProperty StageProperty =
DependencyProperty.Register("Stage", typeof(int), typeof(StagedButton),
new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null,
(d, baseValue) => Math.Min(((StagedButton)d).StageCount, Math.Max(1, (int)baseValue))));
public int StageCount
{
get { return (int)GetValue(StageCountProperty); }
set { SetValue(StageCountProperty, value); }
}
public static readonly DependencyProperty StageCountProperty =
DependencyProperty.Register("StageCount", typeof(int), typeof(StagedButton),
new PropertyMetadata(1, null,
(d, baseValue) => Math.Max(1, (int)baseValue)));
protected override void OnClick()
{
var stage = Stage;
Stage = (++stage <= StageCount) ? stage : 1;
base.OnClick();
}
}
StageCount is the number of stages. (d, baseValue) => ... part is to filter out invalid values.
Then define a Style for this Button.
<Style x:Key="StagedButtonStyle" TargetType="{x:Type local:StagedButton}">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="20"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="Background" Value="#c42a1c"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="TextElement.FontWeight" Value="Bold"/>
<Setter Property="TextElement.FontSize" Value="12"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:StagedButton}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
CornerRadius="10">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<!-- Set 4 to StageCount. -->
<Setter Property="StageCount" Value="4"/>
<Style.Triggers>
<!-- Define Background for each Stage (up to 4) except default one. -->
<Trigger Property="Stage" Value="2">
<Setter Property="Background" Value="DodgerBlue"/>
</Trigger>
<Trigger Property="Stage" Value="3">
<Setter Property="Background" Value="Green"/>
</Trigger>
<Trigger Property="Stage" Value="4">
<Setter Property="Background" Value="DimGray"/>
</Trigger>
</Style.Triggers>
</Style>
You can increase the number of stages if you wish.
Its usage will be as follows:
<local:StagedButton Style="{StaticResource StagedButtonStyle}">
<TextBlock Text="{Binding Stage, RelativeSource={RelativeSource AncestorType={x:Type local:StagedButton}}, StringFormat=Stage {0}}"/>
</local:StagedButton>
I have a button style. I can't change CornerRadius for Border, what is in Template.
Style:
<Style TargetType="Button" x:Key="Circle">
<Setter Property="Background" Value="#373737"/>
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="Bord1" CornerRadius="20" Background="{TemplateBinding Background}">
<Grid>
<TextBlock Name="tx" Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="{TemplateBinding FontSize}" Foreground="White"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#EBEBEB" />
<Setter TargetName="tx" Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" >
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="#F3F3F3" Offset="0.35"/>
<GradientStop Color="#FFC9C7BA" Offset="0.95"/>
<GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter TargetName="tx" Property="RenderTransform" >
<Setter.Value>
<TranslateTransform Y="1.0" />
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I wrote this code, but it does not help me.
Style A = Application.Current.Resources["Circle"] as Style;
Setter A1 = (Setter)A.Setters[2];
ControlTemplate C1 = (ControlTemplate)A1.Value;
Border B = (Border)C1.LoadContent();
B.SetValue(Border.CornerRadiusProperty, new CornerRadius(2));
You can use your style like this:
Change the Fixed Cornerradius in your Template to a Template Binding
Create a new Class like:
public class MyButton : Button {
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
"CornerRadius", typeof(CornerRadius), typeof(MyButton), new PropertyMetadata(default(CornerRadius)));
public CornerRadius CornerRadius {
get { return (CornerRadius) GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
}
use the class like this in your style and xaml:
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="{Binding Path=Content.Title, ElementName=MainFrame}" Height="450" Width="800">
<Window.Resources>
<Style TargetType="local:MyButton" x:Key="Circle">
<Setter Property="Background" Value="#373737"/>
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyButton">
<Border Name="Bord1" CornerRadius="{TemplateBinding CornerRadius}" Background="{TemplateBinding Background}">
<Grid>
<TextBlock Name="tx" Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="{TemplateBinding FontSize}" Foreground="White"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#EBEBEB" />
<Setter TargetName="tx" Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" >
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="#F3F3F3" Offset="0.35"/>
<GradientStop Color="#FFC9C7BA" Offset="0.95"/>
<GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter TargetName="tx" Property="RenderTransform" >
<Setter.Value>
<TranslateTransform Y="1.0" />
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel>
<local:MyButton Style="{StaticResource Circle}" CornerRadius="10"></local:MyButton>
</StackPanel>
</Window>
UPDATE:
Or you can Change the CornerRadius for your Border programatically like:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
Loaded += WasLoaded;
}
private void WasLoaded(object sender, RoutedEventArgs e) {
var children = VisualTreeHelper.GetChildrenRecursive(Button1);
foreach (var child in children.OfType<Border>()) {
if (child.Name == "Bord1") {
child.CornerRadius = new CornerRadius(1);
break;
}
}
}
}
public static class VisualTreeHelper {
/// <summary>
/// Enumerates through element's children in the visual tree.
/// </summary>
public static IEnumerable<DependencyObject> GetChildrenRecursive(this DependencyObject element) {
if (element == null) {
throw new ArgumentNullException("element");
}
for (var i = 0; i < System.Windows.Media.VisualTreeHelper.GetChildrenCount(element); i++) {
var child = System.Windows.Media.VisualTreeHelper.GetChild(element, i);
yield return child;
foreach (var item in child.GetChildrenRecursive()) {
yield return item;
}
}
}
}
In the following Window I define a trigger for IsMouseOver. The background color is changed correctly, but it has an gradient effect. See the pic below. How to get rid of the effect?
Only Theme.DataGrid.Row.Background.Hover is moved from separate style file to code excerpt below.
<Window x:Class="MyCompany.Application.Shared.UI.Dialogs.SomeWindow
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="MainWindow" Height="350" Width="525" Background="#FFF3F3F7">
<Window.Resources>
<SolidColorBrush x:Key="Theme.DataGrid.Row.BorderBrush" Color="#FFF3F3F7" options:Freeze="True" />
<SolidColorBrush x:Key="Theme.DataGrid.Row.Background" Color="White" options:Freeze="True" />
<SolidColorBrush x:Key="Theme.DataGrid.Row.Background.Hover" Color="#FFAEAEB6" options:Freeze="True" />
<SolidColorBrush x:Key="Theme.DataGrid.Row.Background.Active" Color="#FF0D6AA8" options:Freeze="True" />
<SolidColorBrush x:Key="Theme.DataGrid.Row.Background.HoverSelected" Color="#FF009AD9" options:Freeze="True" />
<SolidColorBrush x:Key="Theme.DataGrid.Row.Background.Disabled" Color="#FFAEAEB6" options:Freeze="True" />
<SolidColorBrush x:Key="Theme.DataGrid.Row.Foreground.Selected" Color="White" options:Freeze="True" />
<Style x:Key="GridView.ColumnHeader.Gripper.Style" TargetType="{x:Type Thumb}">
<Setter Property="Width" Value="8" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Cursor" Value="SizeWE" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type GridViewColumnHeader}" >
<EventSetter Event="FrameworkElement.Loaded" Handler="GridViewColumnHeader_Loaded"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="{StaticResource Theme.DataGrid.ColumnHeader.Background}"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="1" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<ContentPresenter Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<Thumb Grid.Column="1" x:Name="PART_HeaderGripper" HorizontalAlignment="Right" Style="{DynamicResource Theme.DataGrid.ColumnHeader.Gripper.Style}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ListView}" >
<Setter Property="BorderThickness" Value="{DynamicResource Theme.DataGrid.BorderThickness}"/>
<Setter Property="Background" Value="{StaticResource Theme.TreeView.Background}"/>
</Style>
<Style TargetType="{x:Type ListViewItem}" >
<Setter Property="Background" Value="White" />
<Setter Property="Foreground" Value="{DynamicResource Theme.DataGrid.Row.Foreground}" />
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Padding" Value="{DynamicResource Theme.DataGrid.Cell.Padding}"/>
<Setter Property="Margin" Value="1"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource Theme.DataGrid.Row.Background.Hover}" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{DynamicResource Theme.DataGrid.Row.Background.Active}"
<Setter Property="Foreground" Value="{DynamicResource Theme.DataGrid.Row.Background.Selected}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{DynamicResource Theme.DataGrid.Row.Background.Disabled}" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True" />
<Condition Property="IsSelected" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="{DynamicResource Theme.DataGrid.Row.Background.HoverSelected}" />
</MultiTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<CheckBox Content="IsGrouped" IsChecked="{Binding IsGrouped}"/>
<ListView Margin="10" ItemsSource="{Binding Users}">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Age" DisplayMemberBinding="{Binding Age}" />
<GridViewColumn Header="Mail" DisplayMemberBinding="{Binding Mail}" />
<GridViewColumn Header="Group" DisplayMemberBinding="{Binding Group}" />
</ListView>
</StackPanel>
</Window>
ViewModel (note that this uses our own ViewModel-class that i.e raises PropertyChanged events)
namespace MyCompany.Application.Shared.UI.Dialogs
{
public class User
{
public string Name { get; set; }
public int Age { get; set; }
public string Mail { get; set; }
public string Group { get; set; }
}
public class SomeWindowViewModel : ViewModel
{
List<User> items = new List<User>();
IEnumerable<User> GetUsers()
{
foreach (var item in items)
{
yield return item;
}
}
public ICollectionView Users { get; }
private bool _isGrouped = false;
public bool IsGrouped
{
get { return _isGrouped; }
set
{
_isGrouped = value;
if (value)
{
Users.GroupDescriptions.Add(new PropertyGroupDescription("Group"));
}
else
{
Users.GroupDescriptions.Clear();
}
}
}
public SomeWindowViewModel()
{
items.Add(new User() { Name = "John Doe", Age = 42, Mail = "john#doe-family.com", Group = "OneGroup1" });
items.Add(new User() { Name = "Jane Doe", Age = 39, Mail = "jane#doe-family.com", Group = "OneGroup1" });
items.Add(new User() { Name = "Sammy Doe", Age = 7, Mail = "sammy.doe#gmail.com", Group = "TwoGroup2" });
items.Add(new User() { Name = "Pentti Doe", Age = 7, Mail = "pena.doe#gmail.com", Group = "TwoGroup2" });
Users = CollectionViewSource.GetDefaultView(GetUsers());
}
}
}
I had some issues with the given code sample, e.g. missing resources or additional options:Freeze="true" which could not be resolved, therefore my solution may look a little different, but I think it does what you want: it removes the gradient effect.
The issue is that the default ListViewItem template has triggers which change the background (as you have found out as well) and the way around is to use a simplified ControlTemplate without any triggers.
This example of a simplified template works and you can put it in your {x:Type ListViewItem} to get a look like shown in the pictures below.
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="true">
<GridViewRowPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
Using that template, this is what it will look like if you first selected "Sammy Doe 7" and then hover over "Jane Doe 39",
and this is how it looks when you select (e.g. click on) "Jane Doe 39":
I'm not entirely sure what you mean with
as jsanalytics points out control template results in rows to be class names and not the data
but as far as I understand it, above code should not lead to that behavior. If it does, let me know and I will find another solution.
I had implemented a template for textbox to show image inside it, but the problem I facing is that I unable to show image dynamically. Here is my code
Window.xaml
<TextBox Style="{StaticResource imageTextBox}" />
Here is my textbox template
<Style TargetType="Control" x:Key="imageTextBox">
<Setter Property="Margin" Value="0,0,0,8"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Control">
<Border x:Name="bg" BorderThickness="1" CornerRadius="3" BorderBrush="Gray">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBox Style="{DynamicResource BasicTextBox}" Grid.Column="1"
Foreground="{TemplateBinding Foreground}"
Background="{TemplateBinding Background}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
MinWidth="340" Margin="1" />
<Image Source="Images/img_1.gif" Width="20"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" TargetName="bg" Value="Black"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderBrush" TargetName="bg" Value="Black"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="BasicTextBox" TargetType="{x:Type TextBox}">
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
You can use a {Binding} for the <Image.Source> property. Here's an example as a LinqPad query (get LinqPad free):
void Main()
{
// Need to parse XAML since LinqPad doesn't have an integrated XAML build
var xaml = #"
<Grid xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
<Grid.Resources>
<Style TargetType=""Control"" x:Key=""imageTextBox"">
<Setter Property=""Margin"" Value=""0,0,0,8""/>
<Setter Property=""Template"">
<Setter.Value>
<ControlTemplate TargetType=""Control"">
<Border x:Name=""bg"" BorderThickness=""1"" CornerRadius=""3"" BorderBrush=""Gray"">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=""30""/>
<ColumnDefinition Width=""*""/>
</Grid.ColumnDefinitions>
<TextBox Style=""{DynamicResource BasicTextBox}"" Grid.Column=""1""
Foreground=""{TemplateBinding Foreground}""
Background=""{TemplateBinding Background}""
FontFamily=""{TemplateBinding FontFamily}""
FontSize=""{TemplateBinding FontSize}""
FontWeight=""{TemplateBinding FontWeight}""
MinWidth=""340"" Margin=""1"" />
<Image Source=""{Binding Image}"" Width=""20""/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property=""IsMouseOver"" Value=""True"">
<Setter Property=""BorderBrush"" TargetName=""bg"" Value=""Black""/>
</Trigger>
<Trigger Property=""IsFocused"" Value=""True"">
<Setter Property=""BorderBrush"" TargetName=""bg"" Value=""Black""/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<TextBox Style=""{StaticResource imageTextBox}"" />
</Grid>
";
// Get some images... these could be in your resources
var png = PngBitmapDecoder.Create(new Uri("https://upload.wikimedia.org/wikipedia/commons/9/97/Esperanto_star.png"), BitmapCreateOptions.None, BitmapCacheOption.Default);
var vm = new ViewModel { Image = png.Frames[0] };
var o = (FrameworkElement)XamlReader.Parse(xaml);
// Set the image source - in this case, a view model
o.DataContext = vm;
// Let LinqPad display it
PanelManager.DisplayWpfElement(o);
// This code is for the example only, to change the image after 2 seconds.
var dispatcher = o.Dispatcher;
Task.Run(async () =>
{
await Task.Delay(2000);
await dispatcher.BeginInvoke((Action)(() =>
{
png = PngBitmapDecoder.Create(new Uri("https://upload.wikimedia.org/wikipedia/commons/f/f6/Lol_question_mark.png"), BitmapCreateOptions.None, BitmapCacheOption.Default);
vm.Image = png.Frames[0];
}));
});
}
// Define other methods and classes here
public class ViewModel : INotifyPropertyChanged
{
private ImageSource _image;
public event PropertyChangedEventHandler PropertyChanged;
public ImageSource Image
{
get
{
return _image;
}
set
{
if (_image == value)
{
return;
}
_image = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Image)));
}
}
}
This example uses a simple view model as the Binding source, but it could be any source. There is also code which changes the Image value after a 2 second delay to show you that it does in fact update. In your code, you'd omit this and use the way you want to update it.
At first it appears:
Then after update:
I'm making a periodic table of elements wpf application and have made my buttons like this:
<!-- RoundedButton.xaml -->
<Style x:Key="ButtonFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border>
<Rectangle SnapsToDevicePixels="true" Margin="4" Stroke="Black" StrokeDashArray="1 2" StrokeThickness="1"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="RoundedButton" TargetType="{x:Type Button}" x:Name="butt">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="3"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="0,0,1,1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="12,12,12,12" BorderThickness="3,3,3,3" RenderTransformOrigin="0.5,0.5" x:Name="border" BorderBrush="Transparent">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1"/>
<SkewTransform AngleX="0" AngleY="0"/>
<RotateTransform Angle="0"/>
<TranslateTransform X="0" Y="0"/>
</TransformGroup>
</Border.RenderTransform>
<Border Background="{TemplateBinding Background}" CornerRadius="12,12,12,12" x:Name="bordertrue">
<Grid>
<Border Opacity="0" x:Name="Shine" Width="Auto" Height="Auto" CornerRadius="12,12,10,10" Margin="0,0,0,0">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Indigo" Offset="0"/>
<GradientStop Color="Crimson" Offset="0.5"/>
<GradientStop Color="Crimson" Offset="0.5"/>
<GradientStop Color="Indigo" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<ContentPresenter VerticalAlignment="Center" Grid.RowSpan="2" HorizontalAlignment="Center" x:Name="contentPresenter"/>
</Grid>
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" TargetName="border" Value="1"/>
<Setter Property="Opacity" TargetName="contentPresenter" Value="0.5"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="RenderTransform" TargetName="border">
<Setter.Value>
<TransformGroup>
<ScaleTransform ScaleX="0.9" ScaleY="0.9"/>
<SkewTransform AngleX="0" AngleY="0"/>
<RotateTransform Angle="0"/>
<TranslateTransform X="0" Y="0"/>
</TransformGroup>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" TargetName="Shine" Value="1"/>
<Setter Property="BorderBrush" TargetName="border" Value="Gold"/>
<Setter Property="Foreground" Value="Gold" />
<Setter Property="FontWeight" Value="ExtraBold"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And this is working perfectly on mouseover. However in my app I have a combination of textbox and listbox which makes me a searchbox. Whenever I search for a particular element I wish to make the same "Shine button" effect as on mouseover in style above
I've tried to do it like this:
private void highlight(string elementName, bool MultiOrSingle)
{
LinearGradientBrush gradient1 = new LinearGradientBrush();
gradient1.StartPoint = new Point(0.5, 0);
gradient1.EndPoint = new Point(0.5, 1);
gradient1.GradientStops.Add(new GradientStop(Colors.Indigo, 0));
gradient1.GradientStops.Add(new GradientStop(Colors.Crimson, 0.5));
gradient1.GradientStops.Add(new GradientStop(Colors.Crimson, 0.5));
gradient1.GradientStops.Add(new GradientStop(Colors.Indigo, 1));
if (MultiOrSingle == true)
{
foreach (Button elementButton in VisualChildren.FindVisualChildren<Button>(this))
{
if (listBox.Items.Contains(elementButton.Name) == true)
{
elementButton.Background = gradient1;
elementButton.FontWeight = FontWeights.Bold;
elementButton.Foreground = Brushes.Gold;
elementButton.BorderBrush = Brushes.Gold;
}
else
{
elementButton.Background = previousBackgroundColors[elementButton.Name];
elementButton.Foreground = previousForegroundColors[elementButton.Name];
}
}
foreach (Button elementButton in VisualChildren.FindVisualChildren<Button>(this))
{
if (elementButton.Name != "play_quiz" &&
elementButton.Name != "show_scoreboard" &&
elementButton.Name != "update" &&
elementButton.Name != "DragDropGames" &&
listBox.Items.Contains(elementButton.Name) == false)
{
elementButton.Background = Brushes.Gainsboro;
elementButton.BorderBrush = Brushes.DarkBlue;
elementButton.FontWeight = FontWeights.Normal;
elementButton.Foreground = Brushes.Black;
}
}
}
else
{
foreach (Button elementButton in VisualChildren.FindVisualChildren<Button>(this))
{
if (elementName == elementButton.Name)
{
elementButton.Background = gradient1;
elementButton.BorderBrush = Brushes.Gold;
elementButton.FontWeight = FontWeights.Bold;
elementButton.Foreground = Brushes.Gold;
}
else
{
elementButton.Background = previousBackgroundColors[elementButton.Name];
elementButton.Foreground = previousForegroundColors[elementButton.Name];
}
}
foreach (Button elementButton in VisualChildren.FindVisualChildren<Button>(this))
{
if (elementButton.Name != "play_quiz" &&
elementButton.Name != "show_scoreboard" &&
elementButton.Name != "update" &&
elementButton.Name != "DragDropGames" &&
elementName != elementButton.Name)
{
elementButton.Background = Brushes.Gainsboro;
elementButton.BorderBrush = Brushes.DarkBlue;
elementButton.FontWeight = FontWeights.Normal;
elementButton.Foreground = Brushes.Black;
}
}
}
with just setting backgrounds brushes etc etc....
However I encountered 2 problems. When doing this in code behind i can change everything but my border brush will remain as it is determined in xaml style I can't change it in code behind don't know why? And after calling this function when I mouse over the buttons they will Shine...however property foreground won't be changed to gold? It will remain black
to demonstrate :
So this is my mouseover "Shine". When I go with mouse over the button it will change it's look like this
So this is my problem I have searched for H..it came back with few results and called function from above as "multi" and selected all results
However this didn't work "elementButton.BorderBrush = Brushes.Gold" it remained transparent as in xaml. And suddenly my Mouseover shine is not the same anymore it's
<Setter Property="Foreground" Value="Gold" />
<Setter Property="FontWeight" Value="ExtraBold"/>
don't seem to be triggering after the function call
To sum it up. I would like to have the same look of the button and shine effect for all my textbox searches
Your Trigger changes the BorderBrush on element named "Border". However in your code behind you are setting the BorderBrush on the button, which does nothing because you don't use the property BorderBrush anywhere in your template. What you need to do is TemplateBinding the Button's BorderBrush property to the template, like the following:
<Border CornerRadius="12,12,12,12"
BorderThickness="3,3,3,3"
RenderTransformOrigin="0.5,0.5"
x:Name="border"
BorderBrush="{TemplateBinding BorderBrush}">
In order to get the FontWeight and Foreground to trigger when the mouse is over the button when properties is set in code behind, one possible solution is the following.
Set the TextBlock property in the ContentPresenter and then use TemplateBinding to set the value.
<ContentPresenter TextBlock.Foreground="{TemplateBinding Foreground}"
TextBlock.FontWeight="{TemplateBinding FontWeight}"
VerticalAlignment="Center"
Grid.RowSpan="2"
HorizontalAlignment="Center"
x:Name="contentPresenter"/>
<Setter Property="TextBlock.Foreground" TargetName="contentPresenter" Value="White" />
<Setter Property="TextBlock.FontWeight" TargetName="contentPresenter" Value="ExtraBold"/>