I want to show my GroupName on left and button "ShowOnly" on the right of header row.
I tried with this code but doesn't works.
Could anyone help me?
Thx
My code :
<Expander IsExpanded="True" >
<Expander.Header>
<DockPanel HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Path=Name}" FontSize="18"></TextBlock>
<Button Style="{StaticResource ButtonStyle}" Content="Show Only" HorizontalAlignment="Right" Padding="15,0,15,0" Click="Button_Click"></Button>
</DockPanel>
</Expander.Header>
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Setter Property="Background" Value="#f0f0f5"></Setter>
<Setter Property="TextElement.FontFamily" Value="Arial Nova"/>
</Style>
</Expander.Style>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
My ButtonStyle :
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#66e0ff" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="15" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="4" Background="{TemplateBinding Background}">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="White" />
<Setter Property="Foreground" Value="#66e0ff" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I tried also with an DockPanel, but same result.
You need to set the HorizontalAlignment property of the ContentPresenter that is defined in the Expander's default control template to Stretch.
The easiest way to do this is probably to handle the Loaded event of the Expander and use a helper method that finds the ContentPresenter in the visual tree:
private void Expander_Loaded(object sender, RoutedEventArgs e)
{
Expander expander = sender as Expander;
System.Windows.Controls.Primitives.ToggleButton HeaderSite = GetChildOfType<System.Windows.Controls.Primitives.ToggleButton>(expander);
if (HeaderSite != null)
{
ContentPresenter cp = GetChildOfType<ContentPresenter>(HeaderSite);
if (cp != null)
cp.HorizontalAlignment = HorizontalAlignment.Stretch;
}
}
private static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
<Expander IsExpanded="True" Loaded="Expander_Loaded">
<Expander.Header>
<DockPanel HorizontalAlignment="Stretch">
<Button Style="{StaticResource ButtonStyle}" Content="Show Only" DockPanel.Dock="Right" Padding="15,0,15,0" Click="Button_Click"></Button>
<TextBlock Text="{Binding Path=Name}" FontSize="18"></TextBlock>
</DockPanel>
</Expander.Header>
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Setter Property="Background" Value="#f0f0f5"></Setter>
<Setter Property="TextElement.FontFamily" Value="Arial Nova"/>
</Style>
</Expander.Style>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
Set width of DockPanel to width of expander so that it will stretch properly.
<DockPanel HorizontalAlignment="Stretch" Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Expander}}, Path=ActualWidth}">
You can refer to these solutions:
https://joshsmithonwpf.wordpress.com/2007/02/24/stretching-content-in-an-expander-header/
Related
I would like to slide the text (marquee text) of the selected item in a combobox, if it's lenght is bigger than the width of the combobox. It can be either automatical or when the user put the mouse over the combobox. The problem is that i have absolutely no idea on how to do that. It's maybe possible to do that with a render transform (previous definition of a textblock inside it)? or with a storyboard?
Here is the xaml that i need to modify
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate DataType="DataGridColumnHeader" >
<ComboBox ItemContainerStyle="{StaticResource SingleSelectionComboBoxItem}" DisplayMemberPath="Oggetto" Width="100" Height="20" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},Path=DataContext.Selezione, UpdateSourceTrigger=LostFocus}" SelectionChanged="SingleSelectionComboBox_SelectionChanged"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
EDIT: the problem is that i don't know which properties should i target in the storyboard
EDIT2: i took the template of the combobox and modified the text box section like this :
<Style x:Key="ComboBoxEditableTextBox" TargetType="{x:Type TextBox}">
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="100" Duration="00:00:10" Storyboard.TargetProperty="X" Storyboard.TargetName="transferCurreny" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
<Setter Property="RenderTransform">
<Setter.Value>
<TranslateTransform x:Name="transferCurreny" X="0"/>
</Setter.Value>
</Setter>
The problem is that this seems to have no effect
EDIT 3: i realized that i had to use the template that use the style i mentioned above
<ControlTemplate x:Key="ComboBoxEditableTemplate" TargetType="{x:Type ComboBox}">
<Grid x:Name="Placement" SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2"
IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}"
Placement="Bottom">
<Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
MinWidth="{Binding ActualWidth, ElementName=Placement}">
<Border x:Name="DropDownBorder"
BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}"
BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
<ScrollViewer x:Name="DropDownScrollViewer">
<Grid RenderOptions.ClearTypeHint="Enabled">
<Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<Rectangle x:Name="OpaqueRect"
Fill="{Binding Background, ElementName=DropDownBorder}"
Height="{Binding ActualHeight, ElementName=DropDownBorder}"
Width="{Binding ActualWidth, ElementName=DropDownBorder}" />
</Canvas>
<ItemsPresenter x:Name="ItemsPresenter"
KeyboardNavigation.DirectionalNavigation="Contained"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Grid>
</ScrollViewer>
</Border>
</Themes:SystemDropShadowChrome>
</Popup>
<Themes:ListBoxChrome x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" Grid.ColumnSpan="2"
RenderMouseOver="{TemplateBinding IsMouseOver}"
RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" />
<TextBox x:Name="PART_EditableTextBox"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource TemplatedParent}}"
Margin="{TemplateBinding Padding}" Style="{StaticResource ComboBoxEditableTextBox}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" >
</TextBox>
<ToggleButton Grid.Column="1"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
Style="{StaticResource ComboBoxToggleButton}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="true">
<Setter Property="Foreground" Value="Black" />
</Trigger>
<Trigger Property="IsDropDownOpen" Value="true">
<Setter Property="RenderFocused" TargetName="Border" Value="true" />
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter Property="Height" TargetName="DropDownBorder" Value="95" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
<Setter Property="Background" Value="#FFF4F4F4" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true" />
<Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false" />
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false" />
</MultiTrigger>
<Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
<Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5" />
<Setter Property="Color" TargetName="Shdw" Value="#71000000" />
</Trigger>
<Trigger Property="ScrollViewer.CanContentScroll" SourceName="DropDownScrollViewer" Value="false">
<Setter Property="Canvas.Top" TargetName="OpaqueRect"
Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}" />
<Setter Property="Canvas.Left" TargetName="OpaqueRect"
Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
the textbox section is the one that use the style. However when i do Template="{StaticResource ComboBoxEditableTemplate}" in the combobox, i cannot see the selected item anymore, even if it's not null
Updated 08/02
Basically in order to avoid the animation issues you are facing - you will need to add a ScrollViewer as a wrapper to the content-site or selection-box TextBlock. You can either do that by using a custom template selector for your ComboBox so as defined below, or provide a custom item-template with ScollViewer.
Secondly, you can either create a custom ComboBox control in C# to bind the above template-selector/item-template and apply slide-animation on MouseEnterEvent; or implement the same in XAML itself.
For this example - have implemented the control in C#, and provided
a sample usage in XAML.
Code for custom control, and template selector
public class SlidingComboBox : ComboBox
{
public static readonly DependencyProperty SlideForeverProperty = DependencyProperty.Register("SlideForever", typeof(bool), typeof(SlidingComboBox), new FrameworkPropertyMetadata(false));
public bool SlideForever
{
get { return (bool)GetValue(SlideForeverProperty); }
set { SetValue(SlideForeverProperty, value); }
}
protected ContentPresenter _parent;
protected DoubleAnimation _animation;
protected TranslateTransform _translate;
protected Storyboard _storyBoard;
public SlidingComboBox()
{
Loaded += ExComboBox_Loaded;
ClipToBounds = true;
//assign template selector - just to re-template ContentSite / selection box
//uncomment this code - if you want to default-template for popup-items
//ItemTemplateSelector = new SlidingComboBoxItemTemplateSelector();
}
private void ExComboBox_Loaded(object sender, RoutedEventArgs e)
{
Loaded -= ExComboBox_Loaded;
//get content-site holder/parent
_parent = this.GetChildOfType<ContentPresenter>();
//setup slide animation
_animation = new DoubleAnimation()
{
From = 0,
RepeatBehavior = SlideForever ? RepeatBehavior.Forever : new RepeatBehavior(1), //repeat only if slide-forever is true
AutoReverse = SlideForever
};
//create storyboard
_storyBoard = new Storyboard();
_storyBoard.Children.Add(_animation);
Storyboard.SetTargetProperty(_animation, new PropertyPath("RenderTransform.(TranslateTransform.X)"));
}
protected override void OnMouseEnter(MouseEventArgs e)
{
//get actual textblock that renders the selected value
var textBlock = _parent.GetChildOfType<TextBlock>();
//and translate-transform for animation
textBlock.RenderTransform = _translate = new TranslateTransform();
//start animation only if text-block width is greater than parent
if (_parent.ActualWidth < textBlock.ActualWidth)
{
_animation.Duration = TimeSpan.FromMilliseconds(((int)textBlock.Text?.Length * 100));
_animation.To = _parent.ActualWidth - textBlock.ActualWidth;
_storyBoard.Begin(textBlock);
}
base.OnMouseEnter(e);
}
protected override void OnMouseLeave(MouseEventArgs e)
{
//stop animation once mouse pointer is off the control
_storyBoard.Stop();
//reset render state
var textBlock = _parent.GetChildOfType<TextBlock>();
textBlock.RenderTransform = _translate = new TranslateTransform();
base.OnMouseLeave(e);
}
}
public class SlidingComboBoxItemTemplateSelector : DataTemplateSelector
{
DataTemplate _selectedItemTemplate;
public SlidingComboBoxItemTemplateSelector()
{
//create datatemplate with ScrollViewer and TextBlock as child
var textBlock = new FrameworkElementFactory(typeof(TextBlock));
textBlock.SetValue(TextBlock.TextWrappingProperty, TextWrapping.NoWrap);
textBlock.SetBinding(TextBlock.TextProperty, new Binding("SelectedValue")
{
RelativeSource = new RelativeSource { Mode = RelativeSourceMode.FindAncestor, AncestorType = typeof(ComboBox) }
});
var scrollViewer = new FrameworkElementFactory(typeof(ScrollViewer));
scrollViewer.SetValue(ScrollViewer.CanContentScrollProperty, true);
scrollViewer.SetValue(ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Hidden);
scrollViewer.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Disabled);
scrollViewer.AppendChild(textBlock);
_selectedItemTemplate = new DataTemplate
{
VisualTree = scrollViewer
};
}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
ComboBoxItem comboBoxItem = container.GetVisualParent<ComboBoxItem>();
if (comboBoxItem == null)
{
//send back only if template requested for ContentSite, and not for combo-box item(s)
return _selectedItemTemplate;
}
return null;
}
}
/// <summary>
/// VisualTree helper
/// </summary>
public static class HelperExtensions
{
public static T GetChildOfType<T>(this DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
public static T GetVisualParent<T>(this DependencyObject child) where T : Visual
{
while ((child != null) && !(child is T))
{
child = VisualTreeHelper.GetParent(child);
}
return child as T;
}
}
Sample usage:
<Window x:Class="MarqueeSample.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:MarqueeSample"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="400">
<Grid Margin="20">
<DataGrid AutoGenerateColumns="False" IsReadOnly="True" Width="225" VerticalAlignment="Center">
<DataGrid.ItemsSource>
<col:Hashtable>
<col:ArrayList x:Key="TestData1">
<sys:String>Tiny</sys:String>
<sys:String>Keep calm and love programming</sys:String>
</col:ArrayList>
<col:ArrayList x:Key="TestData2">
<sys:String>Sample string</sys:String>
<sys:String>Another string to test</sys:String>
</col:ArrayList>
</col:Hashtable>
</DataGrid.ItemsSource>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="100" Binding="{Binding Key}" />
<DataGridTemplateColumn Header="Value" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<local:SlidingComboBox ItemsSource="{Binding Value}">
<local:SlidingComboBox.ItemTemplate>
<DataTemplate>
<ScrollViewer CanContentScroll="True" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled">
<TextBlock Text="{Binding}" />
</ScrollViewer>
</DataTemplate>
</local:SlidingComboBox.ItemTemplate>
</local:SlidingComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
You can also use SlideForever property to manipulate RepeatBehaviour.
<local:SlidingComboBox ItemsSource="{Binding Value}" SlideForever="True" />
I've been looking into this and I think I have your solution. You should combine both a RenderTransform and a Storyboard on the ComboBox ContentPresenter (this is what displays the currently selected item)
<ComboBox Grid.Row="1" Name="MyComboBox" Width="200">
<ComboBox.Resources>
<Style TargetType="ContentPresenter">
<Setter Property="RenderTransform">
<Setter.Value>
<TranslateTransform X="0" Y="0" />
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard x:Name="ScrollItem">
<Storyboard RepeatBehavior="Forever">
<DoubleAnimation Duration="00:00:5" From="0" To="200" Storyboard.TargetProperty="RenderTransform.(TranslateTransform.X)" />
<DoubleAnimation Duration="00:00:5" BeginTime="00:00:5" From="-200" To="0" Storyboard.TargetProperty="RenderTransform.(TranslateTransform.X)" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</ComboBox.Resources>
<ComboBoxItem>
I am combobox value 1
</ComboBoxItem>
<ComboBoxItem>
I am combobox value 2, Hello!
</ComboBoxItem>
</ComboBox>
Having the ComboBox of size 200, scrolling from 0 to 200, then -200 to 0, scrolls the text off the right hand side of the control, and in the left hand side. (You can drop the 2nd DoubleAnimation if you like and set AutoReverse to True to cause the text to bounce back in if you'd rather that. This does not code you around items that are too big for the control, you will need to write some code for the ComboBox so it decides if the currently selected Item is too big, and from code behind (or maybe a custom ComboBox Class) dynamically turn on/off the storyboard.
First iterate through all items of your combobox, check for the width of every items by assigning the text to a label. Then, check width every time, if width of current item gets greater than previous items then change the maximum width.
int DropDownWidth(ComboBox myCombo)
{
int maxWidth = 0;
int temp = 0;
Label label1 = new Label();
foreach (var obj in myCombo.Items)
{
label1.Text = obj.ToString();
temp = label1.PreferredWidth;
if (temp > maxWidth)
{
maxWidth = temp;
}
}
label1.Dispose();
return maxWidth;
}
private void window_loaded(object sender, EventArgs e)
{
comboBox1.DropDownWidth = DropDownWidth(comboBox1);
}
OR
int DropDownWidth(ComboBox myCombo)
{
int maxWidth = 0, temp = 0;
foreach (var obj in myCombo.Items)
{
temp = TextRenderer.MeasureText(obj.ToString(), myCombo.Font).Width;
if (temp > maxWidth)
{
maxWidth = temp;
}
}
return maxWidth;
}
Thanks to those guys got it from here --> Auto-width of ComboBox's content
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 have a datagrid which contains hyperlinks in a DatagridTemplateColumn like the following :
<DataGridTemplateColumn Width="170" SortMemberPath="Joueur.EtatCivil.Joueur_nom" CanUserReorder="False" CanUserResize="True" Header="">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate />
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource DatagridCellHyperlinkStyle}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Padding="{TemplateBinding Padding}" Width="Auto" VerticalAlignment="Center" SnapsToDevicePixels="True">
<TextBlock Foreground="{TemplateBinding Foreground}" Width="Auto" TextTrimming="CharacterEllipsis">
<Hyperlink IsEnabled="{TemplateBinding IsEnabled}">
<InlineUIContainer TextDecorations="{Binding Path=TextDecorations, RelativeSource={RelativeSource AncestorType=TextBlock}}" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=TextBlock}}">
<ContentPresenter Content="{Binding DataContext.Joueur.EtatCivil.NomComplet, RelativeSource={RelativeSource AncestorType=DataGridRow}}"/>
</InlineUIContainer>
<Hyperlink.Style>
<Style TargetType="Hyperlink" BasedOn="{StaticResource HyperlinkStyle}">
<EventSetter Event="Hyperlink.Click" Handler="ClickEvent" />
<EventSetter Event="Hyperlink.MouseEnter" Handler="MouseOverEvent" />
<EventSetter Event="Hyperlink.MouseLeave" Handler="ClicJoueurMouseLeaveEvent" />
</Style>
</Hyperlink.Style>
</Hyperlink>
</TextBlock>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
This works fine and as expected but I have trouble when I just move my cursor hover many lines in a small time (<0.5s maybe).
My MouseEnterEvent calls a method named "Show();" and my MouseLeaveEvent a method named "Hide();"
This show/hide a small popup to display to the user more data. The problem is that my show(); method update a Wpf toolkit chart which seems to have trouble to be updated with this frequency (10 times in 0.5s). The binding seems to "crash" and never works again.
this helped me : Binding update adds news series to WPF Toolkit chart (instead of replacing/updating series) )
I update my chart like this :
this.colonnes.ItemsSource = null;
_DataGraph = new ObservableCollection<GraphiqueValeurs>();
_DataGraph.Add(new GraphiqueValeurs(value, "my string");
this.colonnes.ItemsSource = _DataGraph;
this.colonnes.UpdateLayout();
With the following xaml :
<chartingToolkit:Chart VerticalAlignment="Top" HorizontalAlignment="Center" FontFamily="/BPM2015;component/#Open Sans Condensed" BorderBrush="Transparent" Name="columnChart" Title="Column Series Demo" Foreground="{DynamicResource CouleurTexte}" >
<chartingToolkit:ColumnSeries Name="colonnes" Foreground="{DynamicResource CouleurTexte}" DependentValueBinding="{Binding Valeur}"
IndependentValueBinding="{Binding Name}"
DataPointStyle="{StaticResource ColorByPreferenceColumn}"
>
<chartingToolkit:ColumnSeries.DependentRangeAxis>
<chartingToolkit:LinearAxis Orientation="Y" Minimum="0" Maximum="20" Title="" Foreground="Transparent" ShowGridLines="True">
<chartingToolkit:LinearAxis.MajorTickMarkStyle>
<Style TargetType="Line">
<Setter Property="Visibility" Value="Collapsed" />
</Style>
</chartingToolkit:LinearAxis.MajorTickMarkStyle>
</chartingToolkit:LinearAxis>
</chartingToolkit:ColumnSeries.DependentRangeAxis>
</chartingToolkit:ColumnSeries>
<chartingToolkit:Chart.LegendStyle>
<Style TargetType="Control">
<Setter Property="Width" Value="0" />
<Setter Property="Height" Value="0" />
</Style>
</chartingToolkit:Chart.LegendStyle>
<chartingToolkit:Chart.TitleStyle>
<Style TargetType="Control">
<Setter Property="Width" Value="0" />
<Setter Property="Height" Value="0" />
</Style>
</chartingToolkit:Chart.TitleStyle>
So my question is : How I can avoid all these quick mouseEnter ? I'd like to avoid my mouseEnter function to call the "Show()" method if the cursor doesn't stay at least 0.4s on the hyperlink.
How could I do that ?
This
Thank you
You can use a DispatcherTimer to add a delay to calling your function and combine that with a bool flag that is set to true in the MouseEnter handler and set to false in the MouseLeave handler. Try this:
private DispatcherTimer timer = new DispatcherTimer();
private isMouseOver = false;
...
timer.Interval = TimeSpan.FromMilliseconds(400);
timer.Tick += Timer_Tick;
...
private void MouseEnterHandler(object sender, MouseEventArgs e)
{
isMouseOver = true;
timer.Start();
}
private void MouseLeaveHandler(object sender, MouseEventArgs e)
{
isMouseOver = false;
timer.Stop();
}
private void Timer_Tick(object sender, EventArgs e)
{
if (isMouseOver) Show();
timer.Stop();
}
All, I have the following resources which defines a custom CheckBox and the images to use for the checked/un-checked states.
<sys:String x:Key="Up">
F1 M 37.8516,35.625L 34.6849,38.7917L 23.6016,50.2708L
23.6016,39.9792L 37.8516,24.9375L 52.1016,39.9792L 52.1016,
50.2708L 41.0182,38.7917L 37.8516,35.625 Z
</sys:String>
<sys:String x:Key="Down">
F1 M 37.8516,39.5833L 52.1016,24.9375L 52.1016,35.2292L
37.8516,50.2708L 23.6016,35.2292L 23.6016,24.9375L 37.8516,39.5833 Z
</sys:String>
<Style x:Key="styleCustomCheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<StackPanel Orientation="Horizontal">
<Path x:Name="MyPin" Width="18" Height="18" Stretch="Fill" Fill="#FF000000"
Data="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=(local:CustomCheckBoxClass.IsCheckedOnData)}" />
<ContentPresenter VerticalAlignment="Center" Margin="10,0,0,0" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="MyPin" Property="Data"
Value="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=(local:CustomCheckBoxClass.IsCheckedOffData)}" />
<Setter TargetName="MyPin" Property="Fill" Value="Gray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Where this is used as follows
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Background="Beige">
<CheckBox Height="35"
local:CustomCheckBoxClass.IsCheckedOnData="{StaticResource Up}"
local:CustomCheckBoxClass.IsCheckedOffData="{StaticResource Down}"
Style="{StaticResource styleCustomCheckBox}"
Content="MySolution1" />
<CheckBox Height="35"
local:CustomCheckBoxClass.IsCheckedOnData="{StaticResource Up}"
local:CustomCheckBoxClass.IsCheckedOffData="{StaticResource Down}"
Style="{StaticResource styleCustomCheckBox}"
Content="MySolution2" />
</StackPanel>
I use the following DependencyPropertys to support this
public class CustomCheckBoxClass : DependencyObject
{
public static readonly DependencyProperty IsCheckedOnDataProperty;
public static void SetIsCheckedOnData(DependencyObject DepObject, string value)
{
DepObject.SetValue(IsCheckedOnDataProperty, value);
}
public static string GetIsCheckedOnData(DependencyObject DepObject)
{
return (string)DepObject.GetValue(IsCheckedOnDataProperty);
}
public static readonly DependencyProperty IsCheckedOffDataProperty;
public static void SetIsCheckedOffData(DependencyObject DepObject, string value)
{
DepObject.SetValue(IsCheckedOffDataProperty, value);
}
public static string GetIsCheckedOffData(DependencyObject DepObject)
{
return (string)DepObject.GetValue(IsCheckedOffDataProperty);
}
static CustomCheckBoxClass()
{
PropertyMetadata MyPropertyMetadata = new PropertyMetadata(string.Empty);
IsCheckedOnDataProperty = DependencyProperty.RegisterAttached(
"IsCheckedOnData", typeof(string), typeof(CustomCheckBoxClass), MyPropertyMetadata);
IsCheckedOffDataProperty = DependencyProperty.RegisterAttached(
"IsCheckedOffData", typeof(string), typeof(CustomCheckBoxClass), MyPropertyMetadata);
}
}
Now I want to know how to extend this so I can use more detailed vector graphics. I have some graphics created using Expression Design and I have exported these as XAML files. The mark up for one of these files is
<DrawingBrush x:Key="Layer_1" Stretch="Uniform">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#FF565656" Geometry="M 107.455,171.715L 107.455,29.3347L 220.225,29.3347L 220.225,171.715L 107.455,171.715 Z "/>
<GeometryDrawing Brush="#FF565656" Geometry="F1 M 152.5,298.345L 152.5,201.955L 175.18,201.955L 175.18,298.345L 152.5,298.345 Z "/>
<GeometryDrawing Brush="#FFFFFFFF" Geometry="M 124.15,172.975L 124.15,48.8647L 165.73,48.8647L 165.73,172.975L 124.15,172.975 Z "/>
<GeometryDrawing Brush="#FF565656" Geometry="F1 M 83.1999,208.885L 83.1999,162.895L 244.48,162.895L 244.48,208.885L 83.1999,208.885 Z "/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
How can I include this in a resource dictionary that can be used directly in a Window/Component? I have attempted to change the DependencyProperty to provide access to DrawingBrush and I have changed the XAML to
<CheckBox Height="35"
local:CustomCheckBoxClass.IsCheckedOnData="{StaticResource Layer_1}"
local:CustomCheckBoxClass.IsCheckedOffData="{StaticResource Down}"
Style="{StaticResource styleCustomCheckBox}"
Content="MySolution1" />
Where I reference the relevant ResourceDictionary, but this has not worked.
Thanks for your time.
Edit. based on #HighCore's comment. Lets say I have the following customised Checkbox
<Style x:Key="MheckBox"
TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<StackPanel Orientation="Horizontal">
<Image x:Name="imageCheckBox"
Width="16"
Height="16"
Source="F:\Camus\ResourceStudio\Graphics\Images\UnPinned16.png"/>
<ContentPresenter VerticalAlignment="Center"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="imageCheckBox"
Property="Source"
Value="F:\Camus\ResourceStudio\Graphics\Images\Pinned16.png"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="imageCheckBox"
Property="Source"
Value="F:\Camus\ResourceStudio\Graphics\Images\UnPinned16.png"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
which works great. How can I change the Value="F:\Camus\ResourceStudio\Graphics\Images\UnPinned16.png" to use the vector graphics I have outlined above?
The fact, that the in Template is used to Path and it assumes a string value in the Data parameter. But now you use DrawingBrush, usually it is used for Rectangle control.
So, we change the type of attached depending properties on the type of DrawingBrush:
public static readonly DependencyProperty IsCheckedOnDataProperty;
public static void SetIsCheckedOnData(DependencyObject DepObject, DrawingBrush value)
{
DepObject.SetValue(IsCheckedOnDataProperty, value);
}
public static DrawingBrush GetIsCheckedOnData(DependencyObject DepObject)
{
return (DrawingBrush)DepObject.GetValue(IsCheckedOnDataProperty);
}
static CustomCheckBoxClass()
{
PropertyMetadata MyPropertyMetadata = new PropertyMetadata(null);
IsCheckedOnDataProperty = DependencyProperty.RegisterAttached("IsCheckedOnData",
typeof(DrawingBrush),
typeof(CustomCheckBoxClass),
MyPropertyMetadata);
}
In Style, now change the Path on the Rectangle, like this:
<Style x:Key="styleCustomCheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="FontFamily" Value="Verdana" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<StackPanel Orientation="Horizontal">
<Rectangle Width="16" Height="16"
Fill="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=(local:CustomCheckBoxClass.IsCheckedOnData)}" />
<ContentPresenter VerticalAlignment="Center" Margin="10,0,0,0" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="MyRectangle" Property="Fill" Value="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=(local:CustomCheckBoxClass.IsCheckedOffData)}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am merging two examples found on the internet. One about stretched selection styles and one about multi-selection in a treeview.
I have everything working, except for the indentations of the treeview. I could give all my code, but that wouldn't solve it.
My problem lies in the following method:
public static class TreeViewItemExtensions
{
public static int GetDepth(this TreeViewItem item)
{
FrameworkElement elem = item;
while (elem.Parent != null)
{
var tvi = elem.Parent as TreeViewItem;
if (tvi != null)
return tvi.GetDepth() + 1;
elem = elem.Parent as FrameworkElement;
}
return 0;
}
}
This method tries to retrieve the depth of a treeviewItem in the tree. The problem is: elem.Parent is always null. Which results in depths of 0.
I think this is happening, because I am using an HierarchicalDataTemplate. A part of my xaml looks like this.
<TreeView Name="folderTree"
ItemsSource="{Binding Folders}"
SelectedItemChanged="folderTree_SelectedItemChanged"
HorizontalContentAlignment="Stretch">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Folders}"
DataType="{x:Type Model:IFolder}">
<StackPanel Orientation="Horizontal">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}"
Value="True">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<Image Source="{Binding Converter={StaticResource iconConverter}}" Height="{Binding ElementName=theFile,Path=ActualHeight}"/>
<TextBlock Text="{Binding FileName}" Name="theFile"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
The XAML for my style of the treeview looks like this:
<Style x:Key="{x:Type TreeViewItem}" TargetType="{x:Type TreeViewItem}">
<!-- leaving some stuff out here -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<ControlTemplate.Resources>
<local:LeftMarginMultiplierConverter Length="19" x:Key="lengthConverter" />
</ControlTemplate.Resources>
<StackPanel>
<!-- The upper part of the TreeViewItem -->
<Border Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<!-- The margin is what we try to measure, how can we get the parents from the templatedParents? -->
<Grid Margin="{Binding Converter={StaticResource lengthConverter},
RelativeSource={RelativeSource TemplatedParent},
Path=.}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="19" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ToggleButton x:Name="Expander"
Style="{StaticResource ExpandCollapseToggleStyle}"
IsChecked="{Binding Path=IsExpanded,
RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press"/>
<ContentPresenter x:Name="PART_Header"
Grid.Column="1"
ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Grid>
</Border>
<!-- the children of the TreeViewItem -->
<ItemsPresenter x:Name="ItemsHost" />
</StackPanel>
<!-- leaving some stuff out here with triggers -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How can I make the HierarchicalDataTemplate fill the Parent property?
I'd scan the visual tree instead.
Here is a simple (even not-so-elegant) solution:
public static class TreeViewItemExtensions
{
public static int GetDepth(this TreeViewItem item)
{
DependencyObject target = item;
var depth = 0;
while (target != null)
{
if (target is TreeView)
return depth;
if (target is TreeViewItem)
depth++;
target = VisualTreeHelper.GetParent(target);
}
return 0;
}
}
Cheers.