LIstview items bound but not visible WPF - c#

ItemsSource of ListView shows loaded item but items are not visible in the screen.
<UserControl x:Class="...Controls.ControlToolbar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TuningInterfaceModel.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<local:StringFormatToImageSourceConverter x:Key="StringToImage" />
</UserControl.Resources>
<Grid>
<ListView ScrollViewer.VerticalScrollBarVisibility="Disabled" x:Name="tStack">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<Image Source="{Binding Path=Key, Converter={StaticResource StringToImage}
, ConverterParameter=../Images/ControlIcons/{0}.ico}" />
<TextBlock Text="{Binding Key}" FontSize="10px" Width="60px" Margin="2,0,0,0" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Setter Property="Cursor" Value="/Images/Cursor/grab.cur"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True" />
<Condition Property="local:MouseExtensions.IsMouseLeftButtonDown" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Cursor" Value="/Images/Cursor/Handover.cur" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</UserControl>

Your <Style TargetType="{x:Type ListViewItem}"> is at fault. It is setting Template as a ControlTemplate that only contains triggers without any content.
If my crystal balls don't fail me, you may want to remove the control template and use Style.Triggers instead.
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Setter Property="Cursor" Value="/Images/Cursor/grab.cur"/>
</Trigger>
</Style.Triggers>
<!-- More triggers -->
</Style>

Related

Conditional ControlTemplate based on property of ViewModel

Is it possible to "select" a different control template based on a property of a viewmodel?
I have the following user control template:
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<RadioButton
GroupName="DisplayButtons"
Content="{TemplateBinding Content}"/>
</ControlTemplate>
</UserControl.Template>
Based on a boolean in the viewmodel, I want to use either a RadioButton or a Button.
How can I achieve that?
You could use a Style with a DataTrigger that sets the Template property:
<UserControl>
<UserControl.Style>
<Style TargetType="UserControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="UserControl">
<Button Content="Button" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ViewModelProperty}" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="UserControl">
<RadioButton Content="RadioButton" />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
</UserControl>
It is possible to use different views for each case but this method is more useful in the case of complicated templates.
For the current case, the easiest way is to use Triggers:
Method 1
<UserControl x:Class="Myusercontrolnamespace.Views.Myusercontrol"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" "
mc:Ignorable = "d" Height="auto" Width="auto" >
<UserControl.Resources>
<DataTemplate x:Key="RadioButtontTemplate">
<RadioButton/>
</DataTemplate>
<DataTemplate x:Key="ButtonTemplate">
<Button/>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentControl Content="{Binding }">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource RadioButtontTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsRadioButton}" Value="False">
<Setter Property="ContentTemplate" Value="{StaticResource ButtonTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Grid>
</UserControl>
Method 2
<UserControl x:Class="Myusercontrolnamespace.Views.Myusercontrol"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" "
mc:Ignorable = "d" Height="auto" Width="auto" >
<UserControl.Resources>
<DataTemplate x:Key="RadioButtontTemplate">
<RadioButton/>
</DataTemplate>
<DataTemplate x:Key="ButtonTemplate">
<Button/>
</DataTemplate>
</UserControl.Resources>
<Grid>
<DataTemplate x:Key="globalControlTemplate">
<ContentControl Content="{Binding }">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource RadioButtontTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ConsumerType}" Value="Business">
<Setter Property="ContentTemplate" Value="{StaticResource ButtonTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
<ContentControl Content="{Binding globalControlTemplate}" />
</Grid>
</UserControl>
Cordially

How to change selected item of listbox when clicking on the Button / textbox in ItemTemplate?

in a WPF project I have a ListBox whose ItemsSource is bound to a set of items. I use a DataTemplate in the ItemTemplate of the ListBox to represent the UI of these items.
What I want to happen is that when the user clicks into any part of the DataTemplate for a bound item then the ListBox.SelectedItem is set to the item whose DataTemplate it is. Then the selected Style will be applied. As you can see from the sample code below, clicking on Label is fine. However, controls such as Button and TextBox do not behave as wanted and there are no doubt others too. I suspect it's got something to do with focus.
How might I achieve this?
XAML:
<Window x:Class="ListViewSelectionOverride.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:ListViewSelectionOverride"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox ItemsSource="{Binding}">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border
Name="Border"
Padding="2"
SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="BorderBrush" Value="Blue"/>
<Setter TargetName="Border" Property="BorderThickness" Value="1"/>
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border x:Name="itemTemplateBorder">
<Grid >
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Margin="3,3,3,0" Grid.Row="0" Content="Label"/>
<Button Margin="3,3,3,0" Grid.Row="1" Content="Button"/>
<TextBox Margin="3,3,3,0" Grid.Row="2" Text="TextBox"/>
<CheckBox Margin="3,3,3,0" Grid.Row="3" Content="CheckBox"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Dummy items to generate 4 items in ListBox
DataContext = new object[] { 1, 2, 3, 4 };
}
}
You could handle the PreviewMouseLeftButtonDown event for the Border element in the template and explicitly select the corresponding item:
private void Border_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Border border = sender as Border;
lvv.SelectedItem = border.DataContext;
}
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="Border" Padding="2" SnapsToDevicePixels="true"
PreviewMouseLeftButtonDown="Border_PreviewMouseLeftButtonDown">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="BorderBrush" Value="Blue"/>
<Setter TargetName="Border" Property="BorderThickness" Value="1"/>
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>

Change the visibility of a grid when a button has focus

I am working on a WPF application and I would like to change the visibility of a grid if an only if a button has focus. I have the following code to change the background of the button if it has focus. I know how to do this Programmatically, but I'd like to know how to get the same thing done in XAML.
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="Aqua" />
</Trigger>
</Style.Triggers>
</Style>
You can name your Button and use a DataTrigger:
<Window
...
>
<Window.Resources>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsFocused, ElementName=butt}" Value="True">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<Button x:Name="butt">Hide</Button>
<Grid>
<Label Background="Yellow">Inside Grid</Label>
</Grid>
<Button>Steal focus</Button>
</StackPanel>
</Window>
EDIT
<Window
...
>
<Window.Resources>
<Style x:Key="CollapsedGridStyle" TargetType="{x:Type Grid}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=butt}" Value="True">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<ToggleButton x:Name="butt">Hide</ToggleButton>
<Grid x:Name="GridA"
Style="{StaticResource CollapsedGridStyle}">
<Label Background="Yellow">Grid A</Label>
</Grid>
<Grid x:Name="GridB">
<Label Background="Green">Grid B</Label>
</Grid>
</StackPanel>
</Window>

ItemsPanel Template has no effect

I'm trying to swap the ItemsPanel in a ListBox for a WrapPanel but the ItemsPanelTemplate on the style doesn't seem to be having an effect. The style is found and applied because the border and background colours change, but inspecting with snoop shows no WrapPanel.
<Style x:Key="CocktailGrid" TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="Background" Value="White" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="SelectionMode" Value="Single" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel
IsItemsHost="True"
Width="{Binding
Path=ActualWidth,
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType=
{x:Type ScrollContentPresenter}}}" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Grid.Row="0" Source="{Binding ImageName}" Height="80" Stretch="Uniform"/>
<TextBlock Grid.Row="1" Text="{Binding Name}" TextWrapping="Wrap" TextTrimming="CharacterEllipsis"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The ListBox is declared as:
<ListBox x:Name="lstCocktails" PreviewKeyDown="dg_PreviewKeyDown" ItemsSource="{Binding Source={StaticResource drinksSource}}" SelectedItem="{Binding SelectedItem,ElementName=root,Mode=TwoWay}" Style="{StaticResource CocktailGrid}"
SelectionMode="Single" MouseDoubleClick="lstCocktails_MouseDoubleClick">
Snoop visual tree:
I've overridden ItemsPanels in other parts of the app but for some reason this one is eluding me
Use this instead of ItemsTemplate
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border Background="{TemplateBinding ListBox.Background}" CornerRadius="5">
<WrapPanel IsItemsHost="True"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
It works

WPF change visual state of datatemplate when selected in a listbox

If I have a WPF ListBox which has a basic ItemTemplate that contains a custom user control, how can I tell the user control in the DataTemplate to change its visual state when its selected in the ListBox?
Thanks a lot for any help you can give
You can style the ListBoxItem to trigger on the IsSelected property. Here's an example:
ListBoxItem ControlTemplate Example
and then you use it like this:
<ListBox ItemContainerStyle="{StaticResource yourListBoxItemStyle}">
or directly in the ListBox itself:
<ListBox.ItemContainerStyle>
<Style TargetType=”ListBoxItem”>
...
</Style>
</ListBox.ItemContainerStyle>
Edit:
Here is a complete example with both an ItemTemplate and an ItemContainerStyle that puts a semi-opaque layer on top of the selected item.
<Grid>
<Grid.Resources>
<x:Array Type="sys:String" x:Key="sampleData">
<sys:String>Red</sys:String>
<sys:String>Green</sys:String>
<sys:String>Blue</sys:String>
</x:Array>
<DataTemplate x:Key="listBoxItem">
<Rectangle Fill="{Binding}" Width="100" Height="100"/>
</DataTemplate>
<Style TargetType="ListBoxItem" x:Key="listBoxItemStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<ContentPresenter />
<Rectangle x:Name="Rectangle" Fill="Black" Opacity="0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Rectangle" Property="Opacity"
Value="0.5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ListBox
ItemsSource="{StaticResource sampleData}"
ItemTemplate="{StaticResource listBoxItem}"
ItemContainerStyle="{StaticResource listBoxItemStyle}"
/>
</Grid>
Edit
After a comment, here is the version using a "unified" template:
<Style TargetType="ListBoxItem" x:Key="listBoxItemStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<Rectangle Name="Rectangle" Fill="{Binding}" Width="100" Height="100" Opacity="1"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Rectangle" Property="Opacity"
Value="0.5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Categories

Resources