C# WPF Style TreeViewItem - c#

I made a custom resource dictionary style for a TreeViewItem, but I am having difficulties with it.
<Style x:Key="StageTreeViewItem" TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<Setter Property="Foreground" Value="Gold"/>
<Setter Property="FontFamily" Value="ArialN"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<Grid>
<Image Name="PrimaryButtonImage" Source="pack://application:,,,/Images/TreeViewItem/TreeViewItem_Normal.png"/>
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The content/header of the TreeViewItem does not exist. I put "Stage One" as Header of the TreeViewItem, but it doesn't show up. Also, if I add multiple tree view items on another, it does not expand at all.
Another thing:
How can I remove the highlights when I select the tree view item? I want it to be transparent even when I hover over it and even when I click it. I don't want anything to happen, but I just don't know how, I tried everything.

Your provided code is not making it clear how you're setting header of TreeViewItem.
For other part of the question, you can use Triggers for events happening in WPF forms. Also have a look at this link, as you'll have to define a template for changing background color on mouse hover.
IsMouseOver Trigger not working in WPF

Related

How do I remove the borders separating the headers in a Listview in XAML (WPF)?

I am making a ListView which loads users in from an Active Directory. To accomplish the brand/styling of the company I am developing the application for I would like to tweak some of the styling of the ListView element.
I have made it so the border of the headers in the Listview are transparent. In the editor in Visual Studio it looks how I want it to be, but when I look at the headers in the ListView in runtime I still get to see borders separating the headers (See image below).
https://i.gyazo.com/99dc8d60d6c5b2e1761456df685d850f.png
I have already tried Googling and I even went to the second page of the Google search result. Can you imagine?
Down here is the style I have used for the headers in my XAML file
<Style x:Key="ListViewHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="BorderBrush" Value="Transparent"></Setter>
<Setter Property="IsHitTestVisible" Value="False"></Setter>
</Style>
What I want is to remove those borders separating the headers in my ListView element.
You can override the template of the GridViewColumnHeader
<Window.Resources>
<Style x:Key="GridHeader" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
<TextBlock Text="{TemplateBinding Content}" Padding="5"
Width="{TemplateBinding Width}" TextAlignment="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<ListView>
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource GridHeader}">
</ListView.View>
</ListView>
Solution taken form here: Remove Separators in ListView Columns - WPF

Hide ValidationError border & text on view with a custom Style

In our project we have a LookUp Base ViewModel which has a Required-Attribute on the SelectedItem property. I have another View that uses one of the child LookUps, which should ignore the Required-attribute. I've already overridden the IsValid method in the ViewModel, so saving without caring about the Required works correctly, but unfortunately it's still showing the validation error on the view when I empty the LookUp:
I had a couple of possibilities:
Split the LookUpBaseViewModel into two childs that are also "BaseViewModels", one with the RequiredAttribute and one without. This works, but it seems like a bit too much work and a lot of extra classes for just a single view that doesn't need to show the validation errors on the View.
Replace the RequiredAttribute with a RequiredIf-Attribute and add a boolean IsRequired parameter to the Constructor. This doesn't work since we use AutoFac in our project, so we can't use a boolean parameter for the ILookUpBaseViewModel-interface implementation.
Add a style to the LookUp-ContentControl in the View to hide the ValidationError border & text. This seemed like the easiest solution on paper, and it also makes sense to just hide the unwanted ValidationError border & text.
So, my question, how do I make the style to hide the default WPF validation error (so the red border and the text behind it)? I'm a novice when it comes to styles, but this is what I've tried (and which doesn't do anything it seems):
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="HideValidationErrorContentControlStyle" TargetType="{x:Type ContentControl}" BasedOn="{StaticResource {x:Type ContentControl}}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<!-- Empty -->
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<!-- Empty -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
With the style on my LookUp-ContentControl like this:
<ContentControl x:Name="MyLookup" Style="{StaticResource HideValidationErrorContentControlStyle}"/>
This is the result I want (even when a ValidationError would normally be shown):
Maybe it isn't your LookUp-ContentControl the one showing the error, but another control inside it. A TextBox, maybe?
Also, instead of leaving the ErrorTemplate empty, try to add an AdornedElementPlaceholder.
<Style x:Key="HideValidationErrorContentControlStyle" TargetType="{x:Type ContentControl}" BasedOn="{StaticResource {x:Type ContentControl}}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<AdornedElementPlaceholder />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
It's likely this isn't needed, but better be safe than sorry.

How to change default mouse hover behavior on dynamically generated buttons

I am a relatively new user of WPF and have run into a problem regarding dynamic Button generation and Buttons' default hover properties.
I am currently working on an application where a significant number of buttons are being generated on a Canvas in the code behind. The contents of each button are unique images referenced by an array of objects containing Uri strings. This array is populated by reading in a file containing these Uri strings, so the number and placement of buttons on this canvas vary based on which file is being read.
For the most part, the appearance of the Canvas when the application runs is what was intended, however hovering over any of the Buttons replaces the image with the default blue background for the duration that the mouse overlaps.
Here is an example of the code that I am using to generate the buttons:
exampleButton = new Button { Content = "Name", Width = 50, Height = 65, Background = new ImageBrush(new BitmapImage(new Uri(#object.UriString, UriKind.Relative))) };
exampleButton.Style = exampleStyle;
exampleCanvas.Children.Add(exampleButton);
Please understand that I have omitted pieces of code irrelevant to my question.
Here is an example of the style that was used, also in the code behind:
exampleStyle = new Style(typeof(Button));
exampleStyle.Setters.Add(new Setter(Button.ForegroundProperty, Brushes.Transparent));
exampleStyle.Setters.Add(new Setter(Button.BorderBrushProperty, Brushes.Transparent));
Together these achieve the effect I am trying to create, barring hover behavior.
So far I have tried appending ControlTemplate overrides into the style declaration but am unsure of how that translates from XAML to the C# code behind. I have also tried creating and binding button templates created in the XAML but I haven't had success in finding explanations or tutorials that apply to my situation.
Any help to accomplish this via the code behind would be greatly appreciated. Of course, if I'm doing this really unconventionally and there is a more standard way of doing things I am all ears.
EDIT:
This is the XAML I am using to declare the style that my dynamically generated buttons are using.
<Style x:Key="MySuperButtonStyle" TargetType="{x:Type Button}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Width" Value="50" />
<Setter Property="Height" Value="65" />
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
Using this call to assign the style in the code behind:
exampleButton.Style = (Style)FindResource("MySuperButtonStyle");
This is happening because the default Button control style has a trigger that changes the Background property of the button when the mouse hovers over it. You need to use a custom style for the button:
<Style x:Key="MySuperButtonStyle" TargetType="{x:Type Button}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Width" Value="50" />
<Setter Property="Height" Value="65" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here the width and the height are set using the style, so you no longer need to set those properties in code. The control template has been changed so it consists only of a Border element with the content inside of it. There are no triggers at all, so the button won't change its appearance when clicked or hovered over.
In your code all you need to do is obtain a reference to this style then assign that to the Style property when you are creating the button.
Having said all this, in WPF you rarely need to create controls in code. Instead you should really be using the MVVM (Model-View-ViewModel) pattern and data binding. You probably shouldn't be creating styles and setters in code either.

Wpf, style is not being applied

I've written a user control with popup, who's content is being set outside the control. The ControlTemplate of that control looks like the following:
<ControlTemplate TargetType="local:InfoIcon">
<Grid>
<ToggleButton x:Name="HelpButton" Style="{StaticResource HelpButton}" />
<Popup PlacementTarget="{Binding ElementName=HelpButton}" Placement="Bottom"
IsOpen="{Binding ElementName=HelpButton, Path=IsChecked, Mode=TwoWay}" StaysOpen="False">
<Border BorderBrush="#767676" BorderThickness="1"
Background="#f1f2f7">
<Border.Resources>
<!-- Important -->
<Style TargetType="Label">
<Setter Property="Foreground" Value="#575757" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="#575757" />
</Style>
<!-- /Important -->
</Border.Resources>
<ContentPresenter Content="{TemplateBinding HelpContent}" />
</Border>
</Popup>
</Grid>
</ControlTemplate>
The Important part - I want to assign custom styles to items, which are being put inside the popup (it serves as a clickable hint)
I'm using my control in the following way:
<local:MyControl>
<local:MyControl.HelpContent>
<TextBlock>Ala ma kota</TextBlock>
</local:MyControl.HelpContent>
</local:MyControl>
But despite styles in the Border, TextBlock's text's color always inherit the value from its parent (checked using Snoop) - resulting in white text on white background.
You can downlad the small PoC application, which demonstrates the problem.
My observations:
The styling does work for Label. It only doesn't work for TextBlock.
When I add TextBlock.Foreground="Red" to the Border, TextBlock becomes red, still ignoring style (but now using color from Border).
Snoop informs, that this TextBlock actually has the Style resolved correctly. But despite it shouldn't, it uses the inherited value instead of one specified in the style.
How can I solve this problem and why does it occur?
I received answer on Microsoft forums; I'll leave it here in case someone encounters the same problem.
The difference is that a TextBlock is not a control, i.e. it doesn't have any ControlTemplate and because of this the implicit style doesn't get applied to it when it is located inside the StackPanel. Please see the following page for more information: http://blogs.msdn.com/b/wpfsdk/archive/2009/08/27/implicit-styles-templates-controls-and-frameworkelements.aspx
You could use Label elements or set the style for the TextBlock elements explicitly.
-- Magnus (MM8)
Edit2
I've set the Foreground of the UserControl to something else. This behavior is because the child TextBlock controls of the UserControl inherit the Foreground-Settings somehow. This has nothing to do with the popup or some other approaches we tried yet.
I've stumbled upon another question with a similar problems here: Cannot override controls foreground colour in wpf
I suggest to accept this strange behavior and just set a Foreground Color of the UserControl instead:
<Style TargetType="{x:Type local:InfoIcon}">
<Setter Property="Foreground" Value="Red"/>
</Style>
previous Edit
You had my curiousity with this weird behavior, but after looking at your PoC it was rather obvious :) The Popup has some attached Properties TextElement.* where you can style the text elements in the popup. This was new to me, too and I will reseach a bit more afterwards. Nevertheless: Workaround for your Problem is to not style the TextBlock but the Popup instead. your code could look something like following :
<ControlTemplate TargetType="{x:Type local:InfoIcon}">
<ControlTemplate.Resources>
<Style TargetType="Popup">
<Setter Property="TextElement.Foreground" Value="Red"/>
</Style>
<Style TargetType="Label">
<Setter Property="Foreground" Value="Red" />
</Style>
</ControlTemplate.Resources>
<Grid>
<ToggleButton x:Name="TB" Width="16" Height="16"/>
<Popup Placement="Bottom" PlacementTarget="{Binding ElementName=TB}" IsOpen="{Binding ElementName=TB, Path=IsChecked}" StaysOpen="False">
<ContentPresenter Content="{TemplateBinding InfoContent}"/>
</Popup>
</Grid>
</ControlTemplate>
I changed the styles to be outside of the controls, of course you can just use the attached properties of the popup directly. But initially you wanted to know how it works with the styles attached at the border, it does not matter now where you add the styles. You can use a ResourceDictionary for example.
As a suggestion, shouldn't this:
TargetType="local:InfoIcon"
be like this?
TargetType="{x:Type local:InfoIcon}"
Maybe you have some TextBlock style defining that it shouldd take the parent's control foreground.
Did you try to add a BasedOn property like this ?
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="Foreground" Value="#575757" />
</Style>
I tried with your code example and this works :
<ContentPresenter Content="{TemplateBinding InfoContent}">
<ContentPresenter.Style>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="TextBlock.Foreground" Value="Red" />
</Style>
</ContentPresenter.Style>
<ContentPresenter.Resources>
<Style TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="Red" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
That's kind of odd because when I put the Foreground setter for the Label control inside the ContentPresenter.Style then this time it's Label wich doesn't work...I think it's because Label is a considered as a ContentControl whereas TextBlock is just a FrameworkElement.
Had a similar issue caused by another problem:
There is a strange bug in WPF that prevents styles, defined in merged dictionaries, from being applied to the first element:
https://www.engineeringsolutions.de/wpf-fix-style-is-only-applied-to-first-element/

Different tab style depending on tab item template?

I have a tab control with two different potential item templates:
<TabControl ItemTemplateSelector="{StaticResource tabTemplateSelector}"/>
Now, I also have styles for it:
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
...
The thing is, I want the tab item style template to be different depending on the value of ItemTemplateSelector. How can I do this? Basically, I don't want that entire style rule to be applied to every tab item, just the ones with a specific tab item template.
Update: to make it clearer, the style has TargetType set to TabItem. I want to apply that style only to those tab items that have a specific item template.
The ContentPresenter in the ControlTemplate will display what's in the ItemTemplate. So you won't be able to switch the Template from inside the ControlTemplate.
Instead, you could use a DataTrigger to set the Template. The DataTrigger will check if the ItemTemplate that will be generated should have the other Template or not.
You will probably need a converter for this but here is an easy example. Say that your ItemTemplateSelector returns the other DataTemplate if Name is equal to "Tab 2". Then your Style with the DataTrigger would look like this
<Style TargetType="TabItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<!-- Your first Template -->
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Name}" Value="Tab 2">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<!-- Your other Template -->
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>

Categories

Resources