Assume that I have 3 different tab items with browsers and i want all the tab to load and render at the same time once I open my window application.
My question: Is there any approach for every tabs that can render in parallel or thread?
You can hack it using a custom template that uses a ListBox instead of the default ContentPresenter:
<TabControl>
<TabItem Header="A">
<WebBrowser Source="http://www.google.com/" />
</TabItem>
<TabItem Header="B">
<WebBrowser Source="http://www.bing.com/" />
</TabItem>
<TabItem Header="C">
<WebBrowser Source="http://www.yahoo.com/" />
</TabItem>
<Control.Template>
<ControlTemplate TargetType="TabControl">
<DockPanel>
<TabPanel IsItemsHost="True"
DockPanel.Dock="{TemplateBinding TabStripPlacement}" />
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items}"
SelectedIndex="{TemplateBinding SelectedIndex}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter Content="{Binding Content}"
ContentTemplate="{Binding ContentTemplate}"
ContentTemplateSelector="{Binding ContentTemplateSelector}" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Visibility"
Value="Hidden" />
<Style.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Visibility"
Value="Visible" />
</Trigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
</ListBox>
</DockPanel>
</ControlTemplate>
</Control.Template>
</TabControl>
A Window can start in its own separate UI thread. But tabs will be rendered on the UI thread the current Window is started on.
Related
I've binded a List from my code-behind to a ListBox but I'm having difficulty stylizing the look to get what I want. I'd like to show up to 8 images at once, but no more than that without scrolling down. When the window resizes, I would like the image sizes to scale with it but still have no more than 8 showing. Here's my current XAML:
<ListBox ItemsSource="{Binding PictureImagesList}">
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" HorizontalAlignment="Center" VerticalAlignment="Top" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}" >
<Grid Background="{TemplateBinding Background}">
<Border HorizontalAlignment="Center" VerticalAlignment="Center"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="Yellow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Here's a pic of what this XAML produces. As you can see the images are much too large and we only see the top half of the second row. If I mess around with ListBoxItem margin I can get them smaller but this isn't really ideal as it only works if the screen resolution stays the same.
Set your image dimensions to be the same and use a WrapPanel instead:
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Margin="5" >
<Image Source="{Binding}" Stretch="Uniform" Width="400" Height="400"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
Alternatively, if you want a fixed number of columns then don't specify image dimensions at all and instead use a UniformGrid:
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Margin="5" >
<Image Source="{Binding}" Stretch="Uniform" />
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Columns="3" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
UPDATE: I'm at a bit of a loss now to understand exactly what it is you're trying to do, the images you're posting don't match your description. If you want the panels to be square, and the images to scale up to them uniformly with a thin border around them, then there are a few things you'll have to do:
1) change your ListBoxItem ControlTemplate to be a Border with a Transparent background and the ContentPresenter inside it. This will ensure that your yellow border doesn't fill the whole box, and that the rest of the box doesn't highlight when selected, but that you can still click anywhere on it to select it.
2) change your ItemTemplate to be a grid (so that it fills all available space) with a border centered in the middle of it with padding (so that you'll be able to see the yellow border when selected), then put your Image content inside that but wrap.
This should do the job:
<Style TargetType="{x:Type ListBox}" x:Key="PictureListBoxStyle">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Grid Margin="5">
<Border Padding="5" HorizontalAlignment="Center" VerticalAlignment="Center">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="Transparent" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}}" Value="True">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Image Source="{Binding}" Stretch="Uniform" />
</Border>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Columns="3" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
</Style>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}" >
<Border Background="Transparent">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If that still isn't it then you'll need to define your requirements more clearly.
You could use a UniformGrid as ItemsPanel with appropriate HorizontalAlignment and VerticalAlignment. Also remove the redundant Border element from the DataTemplate.
<ListBox ItemsSource="{Binding PictureImagesList}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Width="200" Height="200" Margin="5" Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Update: In order to have the yellow selection border directly around the image, use a ListBoxItem Style like shown below. To have the images scaled to (a fraction of) the full ListBox width, add an appropriate ControlTemplate.
<ListBox ItemsSource="{Binding PictureImagesList}">
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="LightGray" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}" >
<Grid Background="{TemplateBinding Background}">
<Border HorizontalAlignment="Center" VerticalAlignment="Center"
BorderThickness="5"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="Yellow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
When a TextBox element has an error The custom adorner doesn't resize the StackPanel the Textbox control lies in:
Using DockPanel.Bottom causes the adorner to overlap on the Textbox below.
The code I shamelessly lifted off http://hirenkhirsaria.blogspot.ie/2013/05/wpf-input-validation-using-mvvm.html:
<ControlTemplate.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
</ControlTemplate.Resources>
<DockPanel LastChildFill="true">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Border>
<AdornedElementPlaceholder Name="customAdorner">
<Border BorderBrush="#DC000C" BorderThickness="1.3" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
Sure, I could use Z Index but I don't like it.
Is there a way to cause the StackPanel to resize on error?
I was thinking of adding a ContentTemplate after each Textbox control:
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
The ContentTemplate generates an error info DataTemplate which I believe should cause the StackPanel to resize.
But I can't figure out how the binding to (Validation.Errors)[0].ErrorContent} should be done.
My terrible attempt:
<UserControl.Resources>
<DataTemplate x:Key="errorinfo">
<TextBlock>Hello World</TextBlock>
</DataTemplate>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<StackPanel>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
</StackPanel>
<ContentControl >
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=name, Path=(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding ElementName=name, Path=(Validation.Errors)[0].ErrorContent}"> </TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>
I can't reuse the datatemplate though!
My question is similar to: WPF- Validation -The validation error message goes behind the other controls because of AdornerDecorator
I just want a different solution.
Any ideas? Thanks
Adorner layers sit separate from the main rendering layers in WPF. A good way to think of an Adorner is simply as a graphical overlay layer which encompasses the shape of the Control it's element tags surround (similar to the behaviour of a Border for example).
You don't need a separate AdornerDecorator for every Control. This means the ideal solution would be to add the AdornerDecorator at the highest level possible such as your Window so that you are always guaranteed an Adorner scope.
I can't believe it! Figured it out myself :D
<UserControl.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
<DataTemplate x:Key="errortemplate">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding Path=(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
<Style x:Key="ContentControlErrorTemplate" TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
<ContentControl Style="{StaticResource ContentControlErrorTemplate}">
</ContentControl>
</StackPanel>
If you have ideas to improve it please let me know. I'm not sure how efficient it is but it works.
I have a wpf application, here i've made a contentcontroller that has a label and a button. this will be used as an overlay when something is loading.
the .cs file
namespace VLC.WPF.Controls
{
public class LoadingOverlay : ContentControl
{
}
}
the .xaml file
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VLC.WPF.Controls">
<Style TargetType="local:LoadingOverlay">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
<ContentPresenter Content="{Binding OverlayContent}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
all of this will be used like this
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/../Controls/LoadingOverlay.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<controls:LoadingOverlay>
<controls:LoadingOverlay.Resources>
<Style TargetType="controls:LoadingOverlay">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted}" Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</controls:LoadingOverlay.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</controls:LoadingOverlay>
in various usercontrols, it's functioning correctly but the styly doesn't appear to load.
What could be wrong here? the code looks alright so i think it should be loading but it isn't.
in your style try adding the TargetType to your ControlTemplate like this
<ControlTemplate TargetType="local:LoadingOverlay">
What I don't understand is why are you setting the styling in the UserControl Resources and not using Keys to reference styles in your ResourceDictionary. It would keep your overall code much cleaner and you wouldn't have to change each control if you have to make a minor change later... for example:
<Style x:Key="overlayOne" TargetType="local:LoadingOverlay">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:LoadingOverlay">
<Grid>
<Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
<ContentPresenter Content="{Binding OverlayContent}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
And when you call the control in your page
<local:LoadingOverlay Style="{DynamicResource overlayOne}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</local:LoadingOverlay>
and if you find you need to alter the style for another page, instead of doing an inline style for the control - after the originally defined style try this:
<Style x:Key="overlayTwo" TargetType="local:LoadingOverlay" BasedOn="{StaticResource overlayOne}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
This style uses all the information you have already defined and adds another data trigger, or you could override what is there, change other elements in style such the font size or colors.
Then, you just have to use this key when defining your control
<local:LoadingOverlay Style="{DynamicResource overlayTwo}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</local:LoadingOverlay>
Sorry for the long winded answer, but I see this being a potential problem if you have a lot of these controls on different pages and by not keeping all of your styling in the ResourceDictionary
P.S. If your content is going to be the same that could also be part of the style like below
<Style x:Key="overlayOne" TargetType="local:LoadingOverlay">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:LoadingOverlay">
<Grid>
<Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
And then you only need on your page
<local:LoadingOverlay Style="{DynamicResource overlayOne}"/>
You actually override the style within the LoadingOverlay resources.
Replace <Style TargetType="controls:LoadingOverlay"> by the following <Style TargetType="{x:Type controls:LoadingOverlay}" BasedOn="{StaticResource {x:Type controls:LoadingOverlay}}"> and voila!
The resource must be defined before the UI element that will be using it. If a control uses a style resource, that style must be higher in the visual tree.
Move the style to the UserControl resources
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/../Controls/LoadingOverlay.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="controls:LoadingOverlay">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted}" Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<controls:LoadingOverlay>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</controls:LoadingOverlay>
I am making a user control that is databound. The query results include a collection of objects (A) where A has a collction of other results (B). So A contains multilple B.
in the user control I want to represent the collection A as expanders and B as buttons inside of the expanders. This is what I got
<UserControl x:Class="GuideLib.ModuleControls.uclQuestions"
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"
d:DesignHeight="300" d:DesignWidth="300">
<ItemsControl x:Name="ictlAnswers" ItemsSource="{Binding}" Background="Gray">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander ExpandDirection="Down" Background="DarkGray">
<Expander.Header>
<TextBlock Text="{Binding Path=Name}" Foreground="White"/>
</Expander.Header>
<ListBox x:Name="SubListBox" ItemsSource="{Binding Path=Question}" Background="Gray" Foreground="White" HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<Button Content="{Binding Path=Name}" Margin="10,2,2,2" HorizontalAlignment="Stretch" Tag="{Binding Path=ID}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Gray" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Orange" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have multiple problems.
1: I can not get the buttons in the expanders to strech horizontally
2: How can I set the Tag property of the button to be the whole object of B
3: Why does the default mouseover effect still execute.
Thanks
Ok here goes:
1. You need to set HorizontalContentAlignment="Stretch" on the ListBox and on the StackPanel inside DataTemplate set Orientation="Vertical"
2. set Tag="{Binding .}" on the Button
3. Update your Button.Style to something like:
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background"
Value="Gray" />
<Setter Property="OverridesDefaultStyle"
Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="Orange" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
finally before you add Question 4. remember ListBoxItem has a Style of it's own. So to completely override the effect on MouseOver when not on the Button but in the "Item" you have to provide a custom Style for ListBox.ItemContainerStyle
Oh and Start Using Snoop. It helps you debug Layout issues. Think you would have been able to solve problem 1 with it cos it would have shown you that your ContentPresenter of ListBoxItem was using required Width and not Stretching.
Just from taking a quick look at it.. for question 2 try doing this:
<Button Content="{Binding Path=Name}" Margin="10,2,2,2" HorizontalAlignment="Stretch" Tag="{Binding}">
That should make it bind to the items in the ListBox.
This is defined in App.xaml inside <Application.Resources> :
<Style x:Key="borderStyle" TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
And I am using it here inside Window1.xaml :
<ListBox Name="listView1" ItemsSource="{Binding}" Background="Black" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding (FrameworkElement.ActualWidth), RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}" Orientation="Horizontal" ItemWidth="150" ItemHeight="150" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Border BorderThickness="5" BorderBrush="DarkGray" Style="{StaticResource borderStyle}">
<Image Width="120" Height="120" Stretch="Fill" Source="{Binding Image}" />
</Border>
<TextBlock FontFamily="Verdana" Foreground="Orange" Text="{Binding Title}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But it doesn't work, when I mouse over it, the border doesn't change the color.
What am I doing wrong ?
Thanks.
You are overriding the trigger if you define the property directly within the border.
Remove BorderBrush="DarkGray"from this line
<Border BorderThickness="5" BorderBrush="DarkGray" Style="{StaticResource borderStyle}">
so it looks like this
<Border BorderThickness="5" Style="{StaticResource borderStyle}">
and add a setter to your style
<Style x:Key="borderStyle" TargetType="Border">
<Setter Property="BorderBrush" Value="DarkGray" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
As a thumb rule: all properties which should be modified by triggers have to be defined as setters within the style.