I need to reuse some vector images. I've implemented this using styles for a path setting the Data property.
When this style is applied in a DataTemplate set to a ListView, only the first item actually shows the path. The Path is visible in live outline during my debugging session. Design time it does show in each item.
I have already tried to make the style unshared using x:Shared="False" however this causes the hard to understand XBF generation error code 0x09c4. compile error.
<!-- Path Style defined in a seperate resource dictionary -->
<Style x:Key="Icon" TargetType="Path">
<Setter Property="Data" Value="F1 M32,32z M0,0z M8,7L8,8 8,9 5,9 4,9 4,10 4,24 4,25 5,25 27,25 28,25 28,24 28,10 28,9 27,9 24,9 24,8 24,7 23,7 19,7 18,7 18,8 18,9 14,9 14,8 14,7 13,7 9,7 8,7z M10,9L12,9 12,10 12,11 13,11 19,11 20,11 20,10 20,9 22,9 22,10 22,11 23,11 26,11 26,23 6,23 6,11 9,11 10,11 10,10 10,9z"/>
</Style>
<!-- DataTemplate defined in a seperate resource dictionary-->
<DataTemplate x:Key="ListViewItem">
<ViewBox>
<Path Style="{StaticResource Icon}" Fill="{StaticResource IconBrush}"/>
</ViewBox>
</DataTemplate>
<!-- DataTemplate applied on a page -->
<ListView
ItemTemplate="{StaticResource ListViewItem}"
ItemsSource={Binding Items}>
</ListView>
Does anyone have any ideas about what might cause this behaviour and how it can be solved?
This is a known issue since the days with Silverlight. When used inside a style, the Path will only be instantiated once. Unlike in WPF, there's no x:Shared="False" to force creating a new instance every time it's requested.
That leaves you with three other options.
First, you can use the Path directly inside your DataTemplate.
<DataTemplate x:Key="ListViewItem">
<Viewbox>
<Path Data="F1 M32,32z M0,0z M8,7L8,8 8,9 5,9 4,9 4,10 4,24 4,25 5,25 27,25 28,25 28,24 28,10 28,9 27,9 24,9 24,8 24,7 23,7 19,7 18,7 18,8 18,9 14,9 14,8 14,7 13,7 9,7 8,7z M10,9L12,9 12,10 12,11 13,11 19,11 20,11 20,10 20,9 22,9 22,10 22,11 23,11 26,11 26,23 6,23 6,11 9,11 10,11 10,10 10,9z" Fill="Red"/>
</Viewbox>
</DataTemplate>
For more flexibility, you can also use a ContentControl instead.
<Style x:Key="Icon" TargetType="ContentControl">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Path Fill="Red" Data="F1 M32,32z M0,0z M8,7L8,8 8,9 5,9 4,9 4,10 4,24 4,25 5,25 27,25 28,25 28,24 28,10 28,9 27,9 24,9 24,8 24,7 23,7 19,7 18,7 18,8 18,9 14,9 14,8 14,7 13,7 9,7 8,7z M10,9L12,9 12,10 12,11 13,11 19,11 20,11 20,10 20,9 22,9 22,10 22,11 23,11 26,11 26,23 6,23 6,11 9,11 10,11 10,10 10,9z"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="ListViewItem">
<Viewbox>
<ContentControl Style="{StaticResource Icon}"/>
</Viewbox>
</DataTemplate>
The last one is probably the best but it will require some work to change the Data property to a more specific PathGeometry.
<Style x:Key="Icon" TargetType="Path">
<Setter Property="Data">
<Setter.Value>
<PathGeometry FillRule="EvenOdd">
<PathFigure IsClosed="True" StartPoint="0,0">
<LineSegment Point="xxx,xxx" />
<LineSegment Point="xxx,xxx" />
</PathFigure>
</PathGeometry>
</Setter.Value>
</Setter>
</Style>
Related
I am trying to create a 3 horizontal dot menu. My code below sets the 3 dots fine but the menu can't be clicked and doesn't show the menu item with the header "Remove item".
Any ideas why?
<Window.Resources>
<Style TargetType="{x:Type Menu}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Menu}">
<Canvas >
<Path Data="M12.5,6.5 C12.5,9.8137085 9.8137085,12.5 6.5,12.5 C3.1862915,12.5 0.5,9.8137085 0.5,6.5 C0.5,3.1862915 3.1862915,0.5 6.5,0.5 C9.8137085,0.5 12.5,3.1862915 12.5,6.5 z M30.5,6.5 C30.5,9.8137085 27.813708,12.5 24.5,12.5 C21.186292,12.5 18.5,9.8137085 18.5,6.5 C18.5,3.1862915 21.186292,0.5 24.5,0.5 C27.813708,0.5 30.5,3.1862915 30.5,6.5 z M48.5,6.5 C48.5,9.8137085 45.813708,12.5 42.5,12.5 C39.186292,12.5 36.5,9.8137085 36.5,6.5 C36.5,3.1862915 39.186292,0.5 42.5,0.5 C45.813708,0.5 48.5,3.1862915 48.5,6.5 z"
Fill="Black"
HorizontalAlignment="Left"
Stretch="Fill"
Stroke="Black"
VerticalAlignment="Top"
Height="7" Width="23"/>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Menu>
<MenuItem Header="Remove item" FontSize="12" />
</Menu>
</Grid>
The ControlTemplate is supposed to include an <ItemsPresenter /> element for the child items to be generated.
So you should add the <ItemsPresenter /> element to your custom template. You may for example use a Grid or some other Panel as the root element of the template and then add both the Canvas and the ItemsPresenter to it.
I am trying to learn something about WPF and I am quite amazed by its flexibility.
However, I have hit a problem with Styles and DataTemplates, which is little bit confusing.
I have defined below test page to play around a bit with styles etc and found that the Styles defined in <Page.Resources> for Border and TextBlock are not applied in the DataTemplate, but Style for ProgressBar defined in exactly the same way is applied.
Source code (I just use Kaxaml and XamlPadX to view the result)
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="Background" Value="SkyBlue"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="CornerRadius" Value="5"/>
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontWeight" Value="Bold"/>
</Style>
<Style TargetType="{x:Type ProgressBar}">
<Setter Property="Height" Value="10"/>
<Setter Property="Width" Value="100"/>
<Setter Property="Foreground" Value="Red"/>
</Style>
<XmlDataProvider x:Key="TestData" XPath="/TestData">
<x:XData>
<TestData xmlns="">
<TestElement>
<Name>Item 1</Name>
<Value>25</Value>
</TestElement>
<TestElement>
<Name>Item 2</Name>
<Value>50</Value>
</TestElement>
</TestData>
</x:XData>
</XmlDataProvider>
<HierarchicalDataTemplate DataType="TestElement">
<Border Height="45" Width="120" Margin="5,5">
<StackPanel Orientation="Vertical" Margin="5,5" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock HorizontalAlignment="Center" Text="{Binding XPath=Name}"/>
<ProgressBar Value="{Binding XPath=Value}"/>
</StackPanel>
</Border>
</HierarchicalDataTemplate>
</Page.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
<Border Height="45" Width="120" Margin="5,5">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock HorizontalAlignment="Center" Text="Item 1"/>
<ProgressBar Value="25"/>
</StackPanel>
</Border>
<Border Height="45" Width="120" Margin="5,5">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock HorizontalAlignment="Center" Text="Item 2"/>
<ProgressBar Value="50"/>
</StackPanel>
</Border>
</StackPanel>
<ListBox Margin="10,10" Width="140" ItemsSource="{Binding Source={StaticResource TestData}, XPath=TestElement}"/>
</StackPanel>
</Page>
I suspect it has something to do with default styles etc, but more puzzling is why some Styles are applied and some not. I cannot find an easy explanation for above anywhere and thus would like to ask if someone would be kind enough to explain this behaviour in lamens' terms with possible links to technical description, i.e. to MSDN or so.
Thanks in advance for you support!
I discovered a simple workaround for this. For any elements that are not able to search outside the data template encapsulation boundary (i.e. are not being implicitly styled), you can just declare an empty style within the data template for that element type and use the BasedOn attribute of the style to find the correct implicit style outside the data template to apply.
In the example below, the TextBox is able to search outside the data template encapsulation boundary (because it inherits from Control?), but the TextBlock is not able to, so I declare the empty style for it which can search outside the data template.
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}" />
</DataTemplate.Resources>
<DockPanel>
<TextBlock Text="{Binding Name}" />
<TextBox Text="{Binding Value}" />
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
This is actually by design. Elements that do not derive from Control will not pick up implicit Styles, unless they are in the application resources.
This link explains this in more detail, or you can view the Connent bug report.
I've looked into this also, and I personally think it's a bug. I've noticed that the style is set if you name your styles like so:
<Style x:Key="BorderStyle" TargetType="{x:Type Border}">
etc...
and explicitly set your DataTemplate to use those styles:
<HierarchicalDataTemplate DataTemplate="TestElement">
<Border Height="45" Width="120" Margin="5,5", Style="{StaticResource BorderStyle}">
I think that it's possible that for DataTemplates (and maybe ControlTemplates), they default to having a null style, unless you explicitly set them.
That to me is not meant to happen - it's not a logical way of WPF working...
This is because ListBox is a logical parent of your datatemplate items, now remember, all properties those are "inheritable" like font, forecolor etc, are derived from the logical parent and ListBox already overrides it in its own default style, thats why this will not work. However in this case, you can use named styles as Mr. Dave has suggested, but I think if it does not work then this is a known problem in case of List Box etc, you can refere to my question here, i had similar problem in listbox, and the answers in my question are in more detail.
How can I get the binding from the outer ConnectingLine (a custom control that binds to FrameworkElements and connects them with a line) to the inner TextBlocks named "Top" and "Bottom" to work? Note that I want the whole FrameworkElements for position information.
<Grid>
<ConnectingLine From="{Binding ElementName=Button1.Top}" To="{Binding ElementName=Button2.Top}" />
<ConnectingLine From="{Binding ElementName=Button1.Bottom}" To="{Binding ElementName=Button2.Bottom}" />
<ToggleButton x:Name="Button1">
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<Rectangle x:Name="Top" />
<Rectangle x:Name="Bottom" />
</Grid>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<ToggleButton x:Name="Button2">
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<Rectangle x:Name="Top" />
<Rectangle x:Name="Bottom" />
</Grid>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</Grid>
My goal is to be able to bind from within XAML. Ideally with no extra fluff, but a solution involving a custom binding operator or attached properties might be acceptable.
Edit:
How I'd like to have the output:
Each distinct colored column is one of the templated ToggleButtons, already with one dashed ConnectingLine between Top and Bottom elements. The horizontal filled lines are what I'm interested in. Currently I'm achieving what I want from code-behind.
<ToggleButton x:Name="Button">
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<CheckBox x:Name="FindMe" IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsChecked}"/>
</Grid>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
Let me know if it works.
I've got some windows with mainly comboboxes, textboxes, and checkboxes. When you click on one to get focus I need a way to have them be outlined with a colorful box (boss' orders). Is there a way to do this easier than overriding the default style of all of these controls? I've never done that before, so it would take a lot of mucking around on my part to figure it out.
You can try adding a FocusVisualStyle to the Controls that need different focus rectangle styles.
From above link
The second mechanism is to provide a separate style as the value of the FocusVisualStyle property; the "focus visual style" creates a separate visual tree for an adorner that draws on top of the control, rather than changing the visual tree of the control or other UI element by replacing it.
Something like this in your Window's Xaml
<Window.Resources>
<Style x:Key="NewFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border>
<Rectangle Stroke="Red" Margin="2" StrokeThickness="1" StrokeDashArray="1 2" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
or your Application.Xaml file.
<Application.Resources>
<Style x:Key="NewFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border>
<Rectangle Stroke="Red" Margin="2" StrokeThickness="1" StrokeDashArray="1 2" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
Usage:
<ComboBox FocusVisualStyle="{StaticResource NewFocusVisual}" Height="23" HorizontalAlignment="Left" Margin="238,102,0,0" Name="ComboBox1" VerticalAlignment="Top" Width="120" />
<CheckBox FocusVisualStyle="{StaticResource NewFocusVisual}" Content="CheckBox" Height="16" HorizontalAlignment="Left" Margin="238,71,0,0" Name="CheckBox2" VerticalAlignment="Top" />
<TextBox FocusVisualStyle="{StaticResource NewFocusVisual}" Height="23" HorizontalAlignment="Left" Margin="238,144,0,0" Name="TextBox1" VerticalAlignment="Top" Width="120" />
If you want the Focus rectangle to change for every type of focus event Microsoft states that:
From Microsoft: Focus visual styles act exclusively for keyboard focus. As such, focus visual styles are a type of accessibility feature. If you want UI changes for any type of focus, whether via mouse, keyboard, or programmatically, then you should not use focus visual styles, and should instead use setters and triggers in styles or templates that are working from the value of general focus properties such as IsFocused or IsFocusWithin.
Give this a shot it works for a TextBox haven't checked your other Controls
<Application.Resources>
<Style TargetType="TextBox" >
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Control.BorderBrush" Value="Red" />
<Setter Property="Control.BorderThickness" Value="3" />
</Trigger>
</Style.Triggers>
</Style>
</Application.Resources>
I want to take the highlight background off of the radtreeview. I created a style to do this, but I keep getting errors and exceptions such as "Items collection must be empty." If I comment out the style the application works fine, so I know that it is the cause of the problem. I am fairly new to WPF, and I am sure I just don't understand how to use styles yet.
Thanks for your help. Here is the code.
<Grid x:Name="LayoutRoot" Background="Salmon">
<telerik:RadTreeView x:Name="radTreeView" Margin="8" ItemsSource="{Binding Errors}" Background="Salmon" Style="{StaticResource treeStyle}">
<Style TargetType="{x:Type telerik:RadTreeViewItem}" x:Name="treeStyle">
<Setter Property="Focusable" Value="False"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{x:Null}"/>
<Setter Property="BorderBrush" Value="{x:Null}"/>
</Trigger>
</Style.Triggers>
</Style>
<telerik:RadTreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding SubItems}" >
<Grid Background="Salmon">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Description}" IsHitTestVisible="False" />
<ListBox Grid.Row="1" ItemsSource="{Binding Messages}" Margin="20,0,0,0" BorderBrush="#00000000" BorderThickness="0" Background="Salmon" IsHitTestVisible="False" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Message}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</HierarchicalDataTemplate>
</telerik:RadTreeView.ItemTemplate>
</telerik:RadTreeView>
</Grid>
</UserControl>
If you know that this is not going to work, I was also trying to get rid of the highlight with the style code:
<Style TargetType="TreeViewItem">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#FFF"/>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="#000"/>
</Style.Resources>
</Style>
You get exceptions because your style tag is actually an item in the tree, and you have ItemsSource set.
Surround the style with <telerik:RadTreeView.ItemContainerStyle> tag.
This should solve the exception but it will not give you the result that you expect since the control template of the tree view item is actually showing another border that is not affected by the Background property. You will need to change the control template.
Telerik change the styles between releases, so giving you a template of a wrong version will probably won't help you.
But, you can go to the installation folder for Telerik and look for a folder called "Themes". There you'll find a solution with all the themes for telerik.
Choose the one that you use.
Find the resource dictionary for the tree view and copy the style and template for the item to your project.
Change xmlns definitions, make sure you have all the brushes and resources that the style depends upon.
Run to see that the style is ok.
In the template, find the VisualState with x:Name="MouseOver" and delete the storyboard inside it.