Viewport width slightly wider than real view window WPF - c#

I prepared my own DataTemplate to display my own Item class objets. To set the width I use binding to ViewportWidth of ScrollViewer. This is how:
<DataTemplate x:Key="MyItemTemplate">
<Grid Margin="5" HorizontalAlignment="Stretch"
Width="{Binding ViewportWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollViewer}}}">
...
</Grid>
</DataTemplate>
How I display data:
<TabItem Header="Shop">
<!--<ScrollViewer>-->
<ListView Name="ShopListView" ItemsSource="{Binding itemList}"
ItemTemplate="{StaticResource MyItemTemplate}"
ItemContainerStyle="{StaticResource alternatingListViewItemStyle}"
AlternationCount="2"
ScrollViewer.CanContentScroll="True"
/>
<!--</ScrollViewer>-->
</TabItem>
The issue is the grid that makes my DataTemplate is sliglty broader - it overlaps the right border of the View Window.
EDIT
Buttons on their right edges are cut.
<Style x:Key="alternatingListViewItemStyle" TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<!-- setting up triggers for alternate background colors -->
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="#FF4C85FF"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="2">
<Setter Property="Background" Value="#FFFF8C7C"></Setter>
</Trigger>
</Style.Triggers>
</Style>

The default style of the item container element generated by the ListView for each item incorporates some padding. That means, rendered items normally have a width which is slightly smaller than the view port width.
To not let your items cross the right border of the viewport, you could set the padding of the item container to zero. This can easily be done with a simple style for the item container. Since you already provide an item container style, you could just let it set the padding property.
However, this might not be necessary. To stretch the item content across the width of the view port, you don't need to bind the Grid.Width property in your item template to ListView.ViewPortWidth. It can be done simpler: The item container can be instructed to horizontally stretch the item content by setting its HorizontalContentAlignment accordingly. This of course can also be done with the item container style.
The below example style (based on the style given in your question) demonstrates both setting the HorizontalContentAlignment and Padding property. If you want to keep the default padding between the items and the border of the ListView, simply omit the Padding setter from my example:
<Style x:Key="alternatingListViewItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Padding" Value="0" />
<Style.Triggers>
<!-- setting up triggers for alternate background colors -->
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="#FF4C85FF"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="2">
<Setter Property="Background" Value="#FFFF8C7C"></Setter>
</Trigger>
</Style.Triggers>
</Style>

Related

Style on ListView Contents is getting applied to the ListView itself

I've encountered a strange behaviour in WPF/XAML. My intent is to create something like this, using Borders, a ListView, and a style for the Borders:
This is what I think the code should be:
<ListView HorizontalAlignment="Right" Margin="20">
<ListView.Resources>
<Style TargetType="Border">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="150"/>
<Setter Property="Background" Value="Blue"/>
</Style>
</ListView.Resources>
<Border/>
<Border/>
</ListView>
But that code actually produces this:
This lead me to play around a bit and I found something really strange. The Width and Height values in the Style for the Borders are getting applied to the ListView itself!
For example, this code:
<ListView HorizontalAlignment="Right" Margin="20">
<ListView.Resources>
<Style TargetType="Border">
<Setter Property="Height" Value="100"/>//this should do nothing because the borders set their own height
<Setter Property="Background" Value="Blue"/>
</Style>
</ListView.Resources>
<Border Height="20" Width="150"/>
<Border Height="20" Width="150"/>
</ListView>
Produces this:
(The height of the ListView is 100 pixels)
When I change the value of Height in the value of the Style, my expectation is that it applies to the Borders, who then ignore it because they set their own heights. In other words it should have no effect. But When I change Height, the height of the ListView changes.
To make things weirder, the Background value is properly being applied to the Borders. Do I have a misunderstanding about how this code should work? Have I found a bug? What is the right way to do what I am trying to do?
I am using Visual Studio 2022, .NET 6, C# 10.
I figured it out. ListView uses a Border internally for its background. The Style is getting applied to this Border, as well as the Borders that are items in the ListView.
The solution is to use a type other than Border, or to make a user control that wraps Border. Grid works just fine:
<ListView HorizontalAlignment="Right" Margin="20">
<ListView.Resources>
<Style TargetType="Grid">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="150"/>
<Setter Property="Background" Value="Blue"/>
</Style>
</ListView.Resources>
<Grid/>
<Grid/>
</ListView>
Produces this:

Force focus on control via xaml style

I have a treeview and a listbox.
I want to specify on the style trigger-setter option that, when the listbox visibility is Hidden the focus have to return on the treeview.
Is it possibile to condition an user control focus on the state of another user control?
something like
<Style TargetType="{x:Type TreeView}">
<Style.Triggers>
<Trigger Property="Visibility" Value="Hidden">
<Setter Property="IsFocus" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
Yes it is, see the example here
FOR CHILDREN IN CONTAINERS
<StackPanel FocusManager.FocusedElement="{Binding ElementName=lol}">
<TextBox x:Name="lol"/>
<TextBox x:Name="lul"/>
</StackPanel>
FOR SELF
<TextBox FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"/>

WPF Set GroupBox opacity to 60 percent if a checkbox is ticked

Is there any way in XAML to bind the opacity of a GroupBox depending on if a checkbox is ticked or not?
For example, I want a GroupBox to be 100% opacity if the checkbox is ticked, otherwise it will be 60% opacity if the checkbox is un-ticked.
Can I use element binding to achieve this?
Thanks all.
You could use a Style with a DataTrigger that binds to the IsChecked property of the CheckBox:
<CheckBox x:Name="chk" />
<GroupBox>
<GroupBox.Style>
<Style TargetType="GroupBox">
<Setter Property="Opacity" Value="0.6" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked, ElementName=chk}" Value="True">
<Setter Property="Opacity" Value="1" />
</DataTrigger>
</Style.Triggers>
</Style>
</GroupBox.Style>
</GroupBox>

How to avoid childrens of groupbox taking there default styles which are defined in resource or resourcedictionary in wpf

Style defined in Resource
<Setter Property="Background" Value="Red"/>
</Style>enter code here
</Window.Resources>
In window i am adding a groupbox with child label .
<Grid>
<GroupBox Header="Header">
<GroupBox.Resources>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="Background" Value="white"/>
</Style>
</GroupBox.Resources>
<Label Content="dsfdsfdsf" Foreground="Black" />
</GroupBox>
</Grid>
My Expected Result was Label taking background of white . But actually it is taking Red Background (that is defined in style of Resource )
If i set the style of the Label to explicitly null it works fine
Label Content="dsfdsfdsf" Foreground="Black" Style={x:Null}
But Controls to GroupBox are dynamically added so i want to set
Style={x:Null} to all childrens that are being added to Group box
if i set OverrideDefalutStyle to True in Label the content of label is not comming ......................
Label Content="dsfdsfdsf" Foreground="Black" OverridesDefaultStyle="True"
That style in GroupBox.Resources has no effect on the GroupBox itself. The implicit GroupBox's style is the one of its closest ancestor on VisualTree. You put that style in the wrong place.
Or use Style property instead
<Grid>
<GroupBox Header="Header">
<GroupBox.Style>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="Background" Value="white"/>
</Style>
</GroupBox.Style>
<Label Content="dsfdsfdsf" Foreground="Black" />
</GroupBox>
</Grid>
By setting
<Style TargetType="{x:Type GroupBox}">
<Setter Property="Background" Value="White"/>
</Style>
you will set the background of all GroupBox controls within your GroupBox and the GroupBox itself to white.
So if you want to set/override the Background of all Labels within your GroupBox just add an additional Style to your GroupBox targeting Label
<Style TargetType="{x:Type Label}">
<Setter Property="Background" Value="White"/>
</Style>
If you want to reset the style property of your Label just add an empty style definition to your GroupBox
<Style TargetType="{x:Type Label}"/>
The next approach is used on your on risk :)
If you only want to reset the background color, you can do this trick/hack to reset:
<Style TargetType="{x:Type Label}">
<Setter Property="Background" Value="{Binding Background.DefaultValue, RelativeSource={RelativeSource Self}}" />
<Setter Property="Foreground" Value="Black" />
</Style>
Hint: Instead of Background.DefaultValue you can also write Background.ABC the main thing here is that the binding goes wrong.

How does this ItemsContainerStyle know about ItemsControl.AlternationIndex

I've been reading through WPF Unleashed and something has confused me about styles.
<Style TargetType="{x:Type Control}" x:Key="altStyle">
<Setter Property="Background" Value="Green"></Setter>
<Setter Property="Foreground" Value="White" ></Setter>
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="White"></Setter>
<Setter Property="Foreground" Value="Black" ></Setter>
</Trigger>
</Style.Triggers>
</Style>
So I have a style here which can be applied to anything that derives from control. Assuming that's how the TargetType works. The confusing part for me is how it understands what ItemsControl.AlternationIndex is. I'm defining a style for a control, which is higher up the inheritance chain than ItemsControl. It's seems to break the rules of inheritance.
I then have a simple datagrid which uses this style as its ItemsContainerStyle:
<local:MyGrid AlternationCount="2" ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Source}" Grid.Row="3" ItemContainerStyle="{StaticResource altStyle}"></local:MyGrid>
(MyGrid derives from DataGrid)
I'm assuming here that the style is applied to each DataRow in the grid, but how on earth is able to resolve this ItemsControl.AlternationIndex as this certainly does not apply to a DataRow does it? and just for clarity on how it looks:
So the question is. How does a style that applies to a datagrid row manage to resolve a property called ItemsControl.AlternationIndex
As an attached property the AlternationIndex can be set on any dependency object and can potentially be inherited. When the style queries the rows it will find that the attached property has been set on them by the creating ItemsControl (the grid control).

Categories

Resources