Could anyone suggest how I can implement a WPF ListBox that (effectively) has a transparent/hit-test-invisible background, but whose items are still hit-test-visible?
In other words, I'd like to be able to click - through the ListBox's background - to controls underneath it, but still be able to select the ListBox's items.
I have ListBox using a custom layout panel (it's a ListBox because the items need to be selectable). However, I need this panel to be overlayed on top of other controls, allowing them to still be used normally.
I've tried various combinations of Background="Transparent" and IsHitTestVisible="False" but I suspect I might be on the wrong lines...
Hope this makes sense - I'm new to WPF so any guidance will be most appreciated! Thanks.
Try setting the background to "{x:Null} on the ListeItemContainer and the ListBox itself.
Transparent is still hit-testable, which is why you're still getting hit tests on it.
EDIT
I ran WPF Inspector on a sample and found that the ScrollViewer in the default ListBox template was causing mouse clicks to stay in the ListBox.
Here is a ListBox control template that does not include the ScrollViewer. It does allow the mouse to pass through to the TextBox that is behind the listbox, but still allows the user to select items in the listbox.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Window.Resources>
<SolidColorBrush x:Key="ListBorder" Color="#828790"/>
<Style x:Key="ListBoxStyle1" TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource ListBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Width="100">
<TextBox TextWrapping="Wrap">I'm in the background. I'm in the background. I'm in the backgroun.</TextBox>
<ListBox Background="{x:Null}" Style="{StaticResource ListBoxStyle1}">
<ListBoxItem Margin="10" Background="#999">Hello</ListBoxItem>
<ListBoxItem Margin="10" Background="#999">Hello</ListBoxItem>
<ListBoxItem Margin="10" Background="#999">Hello</ListBoxItem>
<ListBoxItem Margin="10" Background="#999">Hello</ListBoxItem>
</ListBox>
</Grid>
</Window>
Related
I want to override all my button's style to a borderless grayish button which highlights when hover on.
I wrote like below:
If I remove the template section (I even have no idea of what does it do), the button will have a border even if I have set BorderThickness to 0.
But if I keep the template section, the button will not change its background color at all.
So what can I do to keep both features and why my xaml won't work?
BTW, where can I find a full list of properties/triggers that I can set for certain type of control like button?
<Style TargetType="{x:Type Button}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="Background" Value="{StaticResource TitleBrush}" />
<Setter Property="Foreground" Value="{StaticResource WhiteTextBrush}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ContentPresenter Content="{TemplateBinding Content}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource HoverBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
Why BorderThickness value not reflected to control?
https://stackoverflow.com/a/16649319/440030
Why your xaml won't work?
Because, you set Template property of button with a simple content presenter, So Button ignore all control property and reflect your template. One way is improve your Template property with a by example label:
<ControlTemplate TargetType="{x:Type Button}">
<Label Content="{TemplateBinding Content}"
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="Black"/>
</ControlTemplate>
Try something like this it will work
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="Rect" Width="100" Height="100" Fill="Aqua"/>
<Viewbox>
<ContentControl Margin="20" Content="{TemplateBinding Content}"/>
</Viewbox>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Rect" Property="Fill" Value="Orange"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Grid.Resources>
<Button Template="{StaticResource buttonTemplate}">OK</Button>
</Grid>
I've defined a control template for my top level items of a menu as follows:
<ControlTemplate x:Key="{x:Static MenuItem.TopLevelItemTemplateKey}" TargetType="MenuItem">
<Border x:Name="Border">
<Grid x:Name="Grid" >
<ContentPresenter
ContentSource="Header"
RecognizesAccessKey="False"
Margin="10,5,50,5"
TextBlock.FontFamily="Segoe UI"
TextBlock.FontSize="14"
TextBlock.Foreground="White"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource ControlMouseOver}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
This is giving me the style I want, however the trigger is only triggered when I hover over the text of the menu. Ideally i want the item to become highlighted when I hover over its parent grid element. Tried changing the trigger to this
<ControlTemplate.Triggers>
<Trigger Property="Grid.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource ControlMouseOver}"/>
</Trigger>
</ControlTemplate.Triggers>
but doesn't work. Any suggestions as to where I'm going wrong?
To make whole Border (or Grid) hit test visible you need to initialize Background property with some Brush. You can set it to Transparent for example
<ControlTemplate x:Key="{x:Static MenuItem.TopLevelItemTemplateKey}" TargetType="MenuItem">
<Border x:Name="Border" Background="Transparent" >
<!-- -->
</Border>
<!-- -->
</ControlTemplate>
i search the web for TextBox with rounded corners and find a xaml code like below:
<Style TargetType="{x:Type my1:CustomTextBox}">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate >
<Border Background="{TemplateBinding Background}" x:Name="Bd"
BorderThickness="2" CornerRadius="5" BorderBrush="#FFF9EAB6">
***<ScrollViewer x:Name="PART_ContentHost" />***
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="#FFC7B0B0"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="#FFC7B0B0"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="False">
<Setter Property="Foreground" Value="#FFC7B0B0"/>
</Trigger>
<Trigger Property="Width" Value="Auto">
<Setter Property="MinWidth" Value="120"/>
</Trigger>
<Trigger Property="Height" Value="Auto">
<Setter Property="MinHeight" Value="27"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
i want to find out what is
<ScrollViewer x:Name="PART_ContentHost" />
in detail and why not properly work my template if delete this line from it,
please tell me completely in detail.
thanks alot.
The part named "PART_ContentHost" contains the control core, this is the textbox itself, besides the adornments. The textbox's code behind will look for it, so if you rename of delete, the control wont work.
In this case, the content is scrollable (as a textbox can scroll text horizontally and vertically).
use this part of xaml deign :
<TextBox x:Name="usernameText" Height="30" Width="300" TextWrapping="Wrap" Text="" FontSize="20" HorizontalContentAlignment="Center" LostFocus="usernameText_LostFocus">
<TextBox.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</TextBox.Resources>
</TextBox>
If you need a simple textbox with rounded corners, you can do it like that:
<Border Padding="5" CornerRadius="5" BorderThickness="1" BorderBrush="LightGray" SnapsToDevicePixels="True" Background="White">
<TextBox Background="Transparent" BorderThickness="0">This is beautifull ;)</TextBox>
</Border>
The ScrollViewer contains the actual content of the control. Your control isn't a real textbox, but actually a border (with rounded corners) surrounding a ScrollViewer, into which you would then need to place your text. If you don't need scrolling, you can replace the ScrollViewer with a text box, i.e.:
change
<ScrollViewer x:Name="PART_ContentHost" />
to
<TextBox x:Name="PART_ContentHost" />
I have a button that flashes.
I would like to change the entire button style from a resource dictionary when ever it flashes.
I would think it would be like this:
DesktopWindow.AlertButton.Style = (Style)DesktopWindow.Resources["GreenAlertButtonStyle"];
But that doesn't work. How do I do this? I cannot simply change the background color (although that's all I really want to do) because I want to preserve the triggers. When ever I change the background of the button right now, the mouseover triggers stop working....
The button:
<Style TargetType="Button" x:Key="BaseAlertButtonStyle">
<Setter Property="ToolTip" Value="Show Alert List"/>
<Setter Property="Effect" Value="{DynamicResource dropShadow}" />
<Setter Property="Background" Value="{DynamicResource AlertButtonBackground}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Border CornerRadius="5" x:Name="ButtonBorder" Margin="0,0,0,0"
VerticalAlignment="Stretch" BorderThickness="0"
BorderBrush="#ffffff" Padding="0"
Background="{TemplateBinding Background}"
HorizontalAlignment="Stretch">
<Image x:Name="alertImage">
<Image.Source>
<BitmapImage UriSource="/resources/alertIcon.png" />
</Image.Source>
</Image>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{DynamicResource ButtonRolloverBackground}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I dont wanna hear it about doing a search for this issue....
Try:
DesktopWindow.AlertButton.Style = FindResource("GreenAlertButtonStyle") as Style;
After setting background explicitly you have to clear BackgroundProperty and then set new style.
button1.ClearValue(BackgroundProperty);
I've got an ObservableCollection<User> full of User objects which implement INotifyPropertyChanged. The collection is set as the DataContext of my Window, which contains a ListBox (whose ItemsSource is also set to the same collection), a number of TextBoxes, and a save Button, standard CRUD setup.
I want to change the background of the save Button (and the background of the row in the ListBox which corresponds to the "current item") if one of the properties of the User objects changes. Should I be looking at styles and triggers?
I have the following Style applied to my save Button, and the User objects have a public bool IsDirty property.
<Style x:Key="PropertyChangedStyle" TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding Source=???, Path=IsDirty}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
<Button ... Style="{StaticResource PropertyChangedStyle}">
I think I'm on the right track, but I don't understand how to point the binding to "the current item in an observable list which is set as the datacontext", where "current item" in this case is described by CollectionViewSource.GetDefaultView(ListOfUsers).CurrentItem (where ListOfUsers is my ObservableCollection<User>).
The DataContext of each of the items in your ListBox will be automatically bound to your User instances, so it is not necessary to set the source in your binding. You can bind directly from the style of your ListBoxItems to properties on your User instances.
You can achieve it like this:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ASD_Answer011.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Window.Resources>
<DataTemplate x:Key="ItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Property1}"/>
<CheckBox IsChecked="{Binding Property2}"/>
</StackPanel>
</DataTemplate>
<Style x:Key="ListBoxItemStyle1" TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsDirty}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Padding" Value="2,0,0,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="Selector.IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource SampleDataSource}}">
<ListBox ItemTemplate="{DynamicResource ItemTemplate}" ItemsSource="{Binding Collection}" ItemContainerStyle="{DynamicResource ListBoxItemStyle1}"/>
</Grid>
</Window>
This is how it looks when the application is running:
WPF supports the idea of a "current item" in a collection, and will track the current item for you. You can write a binding path that refers to a collection's current item.
See the "Current Item Pointers" section on the Data Binding Overview page on MSDN.
I'm thinking that, if your ListBox's ItemsSource is bound to (for example) {Binding ListOfUsers}, then your button could use {Binding ListOfUsers/IsDirty}.
I haven't used this much, but I think you may have to set your ListBox's IsSynchronizedWithCurrentItem property to True to make this work.