I want to change the appearance of the Border of the selected Item in the picture linked below.
I've already been looking around on msdn.com and on the internet, but I've found nothing useful.
How can I do this?
The selection appearance is part of the ControlTemplate for ListViewItem. To modify the template for an entire ListView use the ItemContainerStyle to apply a Style to each item, which can contain a modified version of the template.
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
The default template for ListViewItem is pretty complex so in order to preserve as much of the default behavior as possible and give you a good starting point, it's easiest to use Blend to create a copy for you.
In Blend, right-click your ListView and select:
Edit Additional Templates -> Edit Generated Item Container -> Edit A Copy...
and it will create a Style for you in the form above with the default template filled in. The selection appearance uses a few different elements in the template which you may want to modify - these can be seen by selecting the Selected state in the States panel in Blend and drilling into the highlighted items in the Objects panel.
I've found out another solution that might be helpful for others: override specific brush resources in App.xaml. It works without cloning any default style, and is just as simple as:
<SolidColorBrush x:Key="ListViewItemSelectedBackgroundThemeBrush" Color="myColor1"/>
<SolidColorBrush x:Key="ListViewItemPointerOverBackgroundThemeBrush" Color="myColor2"/>
Of course, there are more bushes that can be overriden, and a list of them can be found here: ListViewItem styles and templates.
Note that this approach changes the appearance for ALL ListViews in the application.
Related
ListView offers a DragItemsStarting event that comes with according event args. However, unlike DragStartingEventArgs - common to other elements - it does not offer a DragUI, as far as I can tell. My only option is to use DragOver event which is very annoying.
So, I instead said I'll make the ListViewItem's content draggable. However, that backfired because now the Click event doesn't get through anymore, or only very rarely. Simply put, I either can customize the DragUI and not click my ListItems, or the DragUI looks bad, but I retain my functionality.
Is it possible to get a custom DragUI and have the click be handled by the ListView?
You can still utilize DragStarting, but you have to add it to the item content itself within your DataTemplate:
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<Grid CanDrag="True" DragStarting="ItemDragStartingHandler">
...
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
If that causes the click event not working properly, you could try customizing the ListViewItem container itself, which might work. Right-click the ListView in the designer or the Document Outline window, select Edit Additional Templates, and then Edit Generated Item Container. From the last menu select Edit a Copy...
You will get a Style which might be quite long, but within it you will find the the following:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ListViewItemPresenter DragStarting="ItemDragStartingHandler" x:Name="Root" ...>
You can apply DragStarting event to the ListViewItemPresenter and that might satisfy your needs.
I have 2 grids which use the same Style. I had to add a DataTrigger where a row is displayed red if a property (from the DataRow) is true.
Unfortunately I only need the DataTrigger on one of those grids. The other grid doesn't even own the property.
I found 2 solutions which feel both dirty:
Add the property to the grid where its not used/displayed but to prevent the error
Add another style which is a copy of the first one but has the DataTrigger on top
Is there a way to apply this DataTrigger to just one grid when two grids are effected by the style which contains the DataTrigger?
Thanks in advance!
You can define a new style based on the one you already have:
<Style x:key="baseStyle>
<!-- Your current style -->
</Style>
<Style x:Key="newStyle" BasedOn="{StaticResouce baseStyle}">
<Style.Triggers>
<!-- Your DataTrigger -->
</Style.Triggers>
</Style>
Then apply baseStyle for one grid and newStyle for the other.
I'm currently trying to find a way to style all controls in a UWP app with the same Style/type. To be specific I want to set OpticalMarginAlignment to TrimSideBearings for every - I mean every TextBlock.
I know I can create a Style in App.xaml without x:Key property like this:
<Style TargetType="TextBlock">
<Setter Property="OpticalMarginAlignment" Value="TrimSideBearings" />
</Style>
But this does not change the style of TextBlocks which are in a DataTemplate (which according to similar questions is by design). However I don't want to have to set a Style for each TextBlock used in a DataTemplate, so I thought about other solutions:
Create a StyledTextBlock element derived from TextBlock (not working cause TextBlock is sealed)
Create a StyledDataTemplate element derived from DataTemplate (not working cause I haven't found anything in DataTemplate I could hook into to load the Style and because there is no DataTemplate.Resources)
Create a StyledTextBlock element derived from UserControl with a TextBlock element inside
Number 3 is even working, though it would require me to create a DependencyProperty for every TextBlock.DependencyProperty I want to use to style the StyledTextBlock like this:
<StyledTextBlock Text="Example" FontSize="10" />
To keep code amount low I could create a TextStyle DependencyProperty in StyledTextBlock and set it like this, but I don't like this solution as well:
<StyledTextBlock Text="Example">
<StyledTextBlock.TextStyle>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="10" />
</Style>
</StyledTextBlock.Style>
</StyledTextBlock>
Does anyone have another idea how to achieve this?
I have a Silverlight application that displays a list of items in a ListBox. Each item represents a different 'page' of my application so I have a style that is applied to the ItemContainerStyle property that looks like this:
<Style x:Key="navigationItemContainerStyle" TargetType="ListBoxItem">
<Setter Property="Margin" Value="5,3"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Cursor="Hand">
<VisualStateManager.VisualStateGroups>
<!-- code omitted --!>
</VisualStateManager.VisualStateGroups>
<Border x:Name="contentBorder"
Background="{StaticResource navigationHighlightBrush}"
CornerRadius="3"
Opacity="0"/>
<ContentControl x:Name="content"
Margin="10,5"
Content="{Binding}"
Foreground="DarkGray"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The style is very simple. It simply displays the Border when the ListBoxItem's visual state is equal to 'Selected'. Notice that the content is hosted by a ContentControl as I want to be able to change the Foreground property when the item is in the 'Selected' state.
This works brilliantly as can be seen by the screenshot below:
Now I want the selected item to invoke navigation so the idea I had was to create a DataTemplate that sets the content of each item to a HyperLinkButton:
<DataTemplate x:Key="navigationListBoxItemTemplate">
<HyperlinkButton Content="{Binding}"
Background="Transparent"/>
</DataTemplate>
Now this doesn't work as the ItemTemplate hosts it's content in a ContentControl rather than a ContentPresenter so I have had to update the ListBoxItem template to use a ContentPresenter instead.
<ContentPresenter x:Name="content" Margin="10,5"/>
I now get the following result:
When I click on the HyperLinkButton the ListBoxItem is now no longer selected (I can click just outside the HyperLinkButton and the ListBoxItem becomes selected). What I really want is for the ListBoxItem to become selected when the HyperLinkButton is clicked. The HyperLinkButton has no concept of selection so I cannot bind to the ListBoxItem's IsSelected property.
Note: The actual navigation works perfectly, the problem is purely with the appearance of the ListBoxItems.
So my questions are:
Can I make it so that when the HyperLinkButton is clicked, the ListBoxItem becomes selected like the first image?
I will also need some way of changing the foreground of the HyperLinkButton when it is selected as this is no longer done in the items template due to me swapping the ContentControl fro a ContentPresenter.
Note: I could probably solve this problem by binding the SelectedItem property of the ListBox to my viewModel and handling the navigation there negating the requirement to have a HyperLinkButton hosted by each ListBoxItem but I am interested in knowing if it is possible using styles and templates to achieve my desired result.
Update
I have tried a couple of things to try and resolve this but so far have been unsuccessful. The first thing I tried was applying a new style to the HyperLinkButton control in my DataTemplate which essentially removes all of the default look and feel from the control but my application still behaves in the way described above.
The second thing I tried was setting the IsHitTestVisible property to false. This allows me to click 'through' the HyperLinkbutton and select the ListBoxItem but this means that the navigation is now no longer invoked.
The ListBoxItem is not selected because the Button (whatever type it is) marks the MouseLeftButtonDown event as Handled. Therefore the required event does not bubble up to the parent ListBoxItem.
Evidently, your ListBoxItem is getting focus from the click (I assume that is the border in your final image), so this must happen regardless.
Under the covers, the ListBoxItem will have a standard LeftMouseButtonDown event handler set up to deal with Selection, and it must have a call to AddHandler to deal with setting focus.
You can achieve something similar by adding your own handler for the event, like so:
listboxitem.AddHandler(UIElement.MouseLeftButtonDownEvent, new System.Windows.Input.MouseButtonEventHandler(MyMouseLeftButtonDownEventHandler), true);
The final parameter instructs the handler to handle handled events...
Attaching this handler I leave to you, but using a behavior is probably the most straight forward. You could event derive a type from Button and have it walk up the Visual Tree to find and select the ListBoxItem... The possibilities are endless.
I am deriving from Combobox to add some additional functionality, such as a checkbox.
The issue is, even with a simple implementation the Items.Add method does not work.
For example, here is the XAML:
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<ComboBox>
</ComboBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The ComboBox is visible, but no information is added when I call the Items.Add method. What do I need to implement from the ComboBox class to achieve this? Do I need to do something with the popup? Add a Textblock?
That doesn't look to me like you're deriving from ComboBox... It looks to me like you're putting a ComboBox inside the ControlTemplate of your custom control.
If you are also deriving your custom control from ComboBox and calling Items.Add on your custom control, then you've basically got two lists of data (one for your custom control and one for the combobox in your controltemplate) and they are not linked in any way.
I'd suggest popping open Expression Blend and taking a look at the control template for a default ComboBox. If you want to derive from ComboBox you can then modify that controltemplate to suit your needs.