Frame doesn't work anymore after adding template - c#

I'm trying to learn WPF, I created a resource dictionary with a template for my Frame but after adding the template the Frame doesn't display my Pages anymore. When I remove the template, everything works again (the pages are properly displayed). What am I doing wrong?
ResourceDictionary.xaml (just very basic)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ControlTemplate x:Key="frameTemplate" TargetType="{x:Type Frame}">
<Grid>
<Border BorderBrush="Tomato" BorderThickness="3" Background="Bisque"/>
</Grid>
</ControlTemplate>
</ResourceDictionary>
MainWindow.xaml
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources/Icons.xaml" />
<ResourceDictionary Source="ResourceDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Controls:MetroWindow.RightWindowCommands>
<Controls:WindowCommands>
<ToggleButton Content="Menu"
IsChecked="{Binding ElementName=Flyout, Path=IsOpen}" Cursor="Hand"/>
</Controls:WindowCommands>
</Controls:MetroWindow.RightWindowCommands>
<Grid>
<Grid x:Name="menu_grid">
</Grid>
<!-- flyout here, the title bar is not overlapped -->
<Controls:Flyout x:Name="Flyout"
Width="200"
Header="Menu"
IsOpen="True"
Position="Left">
<StackPanel>
<Button HorizontalContentAlignment="Center" VerticalAlignment="Center" Margin="10" Click="DriverButton_Click">
<StackPanel Orientation="Horizontal">
<Rectangle Height="16" Width="16" Margin="5">
<Rectangle.Fill>
<VisualBrush Visual="{StaticResource appbar_people}" Stretch="Fill" />
</Rectangle.Fill>
</Rectangle>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">Drivers</TextBlock>
</StackPanel>
</Button>
<Button HorizontalContentAlignment="Center" VerticalAlignment="Center" Margin="10" Click="SeasonButton_Click">
<StackPanel Orientation="Horizontal">
<Rectangle Height="16" Width="16" Margin="5">
<Rectangle.Fill>
<VisualBrush Visual="{StaticResource appbar_calendar}" Stretch="Fill" />
</Rectangle.Fill>
</Rectangle>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">Seasons</TextBlock>
</StackPanel>
</Button>
<Button HorizontalContentAlignment="Center" VerticalAlignment="Center" Margin="10" Click="ConstructorsButton_Click">
<StackPanel Orientation="Horizontal">
<Rectangle Height="16" Width="16" Margin="5">
<Rectangle.Fill>
<VisualBrush Visual="{StaticResource appbar_team}" Stretch="Fill" />
</Rectangle.Fill>
</Rectangle>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">Constructors</TextBlock>
</StackPanel>
</Button>
</StackPanel>
</Controls:Flyout>
<Grid Margin="200 0 0 0">
<Frame x:Name="_mainFrame" Template="{StaticResource frameTemplate}" />
</Grid>
</Grid>
MainWindow.xaml.cs
public partial class MainWindow
{
DriversPage driversPage = new DriversPage();
SeasonPage seasonsPage = new SeasonPage();
ConstructorsPage constructorsPage = new ConstructorsPage();
public MainWindow()
{
InitializeComponent();
}
private void DriverButton_Click(object sender, RoutedEventArgs e)
{
_mainFrame.Navigate(driversPage);
}
private void SeasonButton_Click(object sender, RoutedEventArgs e)
{
_mainFrame.Navigate(seasonsPage);
}
private void ConstructorsButton_Click(object sender, RoutedEventArgs e)
{
_mainFrame.Navigate(constructorsPage);
}
}

When you override a ControlTemplate, you need to supply the entire template for the control. You are only supplying a Grid with a Border in it, so that is all that is going to render. If you look at the example template for Frame, you will see there is a lot more there. I suspect the important piece that you need to display the page is probably the content presenter named "PART_FrameCP". Try adding that to your template.
<ContentPresenter x:Name="PART_FrameCP" />
Named parts are usually important in templates because the control will look for them. Sometimes, unnamed parts are also searched for by type and therefore may be important as well. It is a good idea to read and understand the example template when creating a template of your own.

Related

Display icon over select images in wpf listbox

I've looked at some related answers (Content of a Button Style appears only in one Button instance, and Images only showing in last ListBoxItem), but can't seem to get their answers to work in my example.
My app wpf stack is relatively complex.
I've a UserControl within another window. Within the UserControl, I've a ListBox with nested elements ListBox.ItemTemplate > DataTemplate > Border > Grid > StackPanel
Within the StackPanel is a TextBlock, followed by an Image and a StackPanel.ToolTip
I'm wanting to place an icon over the Image, so I've further obfuscated the image by putting it in a Grid, and adding a ViewBox accessed via a Control Template (as suggested in the above links), so that the ViewBox is centered on the image. Here's the Grid:
<Grid>
<Image RenderOptions.BitmapScalingMode="HighQuality"
Height="{Binding ElementName=_this, Path=ThumbSize.Height}"
>
<gif:ImageBehavior.AnimatedSource>
<MultiBinding Converter="{c:ImageConverter}">
<Binding Path="ThumbLocation" />
<Binding Path="FullName" />
</MultiBinding>
</gif:ImageBehavior.AnimatedSource>
</Image>
<Control Template="{StaticResource PlaySymbol}" Visibility="{Binding PlayVisible}" />
</Grid>
The ViewBox's ControlTemplate is in the UserControl.Resources up at the top
<ControlTemplate x:Key="PlaySymbol" TargetType="{x:Type Control}">
<Viewbox Stretch="Uniform"
RenderTransformOrigin="0.5,0.5"
Opacity="0.75"
x:Shared="False"
>
<Viewbox.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.5" ScaleY="0.5"/>
</TransformGroup>
</Viewbox.RenderTransform>
<ContentControl Content="{StaticResource appbar_control_play}" />
</Viewbox>
</ControlTemplate>
The appbar_control_play is in the Resources directory in an Icons.xaml file.
<Canvas x:Key="appbar_control_play" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="20.5832" Height="31.6667" Canvas.Left="30.0833" Canvas.Top="22.1667" Stretch="Fill" Fill="{DynamicResource BlackBrush}" Data="F1 M 30.0833,22.1667L 50.6665,37.6043L 50.6665,38.7918L 30.0833,53.8333L 30.0833,22.1667 Z "/>
</Canvas>
The goal is to only display the icon for 'play' on movies. I've set the PlayVisible to return the proper visibility for movies, and not for other files. Yet, it is only displaying for the last movie. I've heard that this is the case for controls only able to have one parent. I've tried setting x:Shared="False" on the ViewBox, but to no avail.
The app works, but I've recently decided to add movies to the listing and want to display the play icon over their thumbnails, but not the other items. It seems simple on the outset, but I've yet to figure out what is needed.
Any help would be appreciated, otherwise I feel I may have to resort to overlaying the icon on the actual thumbnails of the movies.
It looks like the problem is not related to the Viewbox but the image resource appbar_control_play it references.
There is no need to add the Viewbox via a Control. Just add it directly to the DataTemplate.
Generally prefer a ContentControl over a templated Control if you wish to display content.
The x:Shared attribute is only required on a UIElement that is not part of a template but defined in a ResourceDictionary. For example, when you define the Viewbox in as a resource, you must set the x:Shared attribute to false. Otherwise it is only allowed to appear once in the visual tree.
In case the image resource is an image file, a proper DataTemplate could look as followed:
<DataTemplate>
<StackPanel>
<Grid>
<Image Source="path to image" />
<Image Source="path to overlay icon"
Stretch="UniformToFill"
Width="50"
Height="50" />
</Grid>
</StackPanel>
</DataTemplate>
In case the icon is a XAML resource like a Geometry or a Segoe MDL2 Assets font icon, the DataTemplate should look as followed:
App.xaml
<Application.Resources>
<Viewbox x:Key="PlayIcon" x:Shared="False">
<TextBlock FontFamily="Segoe MDL2 Assets"
Text="" />
</Viewbox>
<Viewbox x:Key="appbar_control_play"
x:Shared="False">
<Path Width="20.5832"
Height="31.6667"
Stretch="Fill"
Fill="{Binding RelativeSource={RelativeSource AncestroType=ContentControl}, Path=For4ground}"
Data="F1 M 30.0833,22.1667L 50.6665,37.6043L 50.6665,38.7918L 30.0833,53.8333L 30.0833,22.1667 Z " />
</Viewbox>
</Application.Resources>
MyControl.xaml
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid>
<Image Source="path to image" />
<ContentControl Content="{StaticResource appbar_control_play}"
Width="50"
Height="50"
Foreground="Pink" />
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
Not sure what's happening on your side but the following just works:
<Window x:Class="abc.Window1"
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:system="clr-namespace:System;assembly=System.Runtime"
mc:Ignorable="d"
Title="Window1">
<Grid>
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</DataTemplate.Resources>
<Border Width="64" Height="64" BorderBrush="Red" BorderThickness="1">
<Grid>
<TextBlock Text="{Binding}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Rectangle Fill="DeepSkyBlue"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Margin="2"
Width="16"
Height="16"
Visibility="{Binding Converter={StaticResource BooleanToVisibilityConverter}}"
x:Name="Button" />
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
<system:Boolean>True</system:Boolean>
<system:Boolean>False</system:Boolean>
<system:Boolean>True</system:Boolean>
<system:Boolean>False</system:Boolean>
<system:Boolean>True</system:Boolean>
<system:Boolean>False</system:Boolean>
</ListBox>
</Grid>
</Window>

Blur The Background Of A Custom Control

The title might not be clear but I will explain now. I have a custom control that represents a modal (inspired by SingltonSean), When I trigger a command, it shows this modal that covers the rest of the elements behind it, it somewhat acts like a popup. Now I want everything behind it to be blurred. How can I achieve that?
This is my modal custom control:
<Style TargetType="{x:Type viewModel:Modal}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type viewModel:Modal}">
<ControlTemplate.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</ControlTemplate.Resources>
<Grid Visibility="{TemplateBinding IsOpen, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid.Background>
<SolidColorBrush Color="Black" Opacity="0.025" />
</Grid.Background>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" UseLayoutRounding="True" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=border}" />
</Grid.OpacityMask>
<Border x:Name="border" Background="White" CornerRadius="20" />
<Grid Width="500" Height="600">
<StackPanel Width="300" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Padding="10 5" Content="Close Modal" />
</StackPanel>
</Grid>
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You need to apply blur where content is:
<Grid>
<Grid>
<Grid.Effect>
<BlurEffect Radius="20"/>
</Grid.Effect>
<TextBlock Text="Some content I want to blur"/>
</Grid>
<TextBlock Text="Popup"/>
</Grid>
If you want to make a control, which is able to blur something before in visual tree, you still need to apply effect to it. One possibility is to use attached behavior:
public static class Behavior
{
public static UIElement GetBlurTarget(DependencyObject obj) => (UIElement)obj.GetValue(BlurTargetProperty);
public static void SetBlurTarget(DependencyObject obj, UIElement value) => obj.SetValue(BlurTargetProperty, value);
public static readonly DependencyProperty BlurTargetProperty =
DependencyProperty.RegisterAttached("BlurTarget", typeof(UIElement), typeof(Behavior), new PropertyMetadata((d, e) =>
{
if (e.NewValue is UIElement element)
element.Effect = new BlurEffect { Radius = 20 };
}));
}
Then layout should be like this:
<Grid>
<Grid x:Name="container">
<TextBlock Text="Some content I want to blur" />
</Grid>
<TextBlock Text="Popup" local:Behavior.BlurTarget="{Binding ElementName=container}"/>
</Grid>
Both cases will produce same result:

How to get a not selected item from wpf's listview

I'm working on a image displayer and I custom a datatemplate of listview(it's the images container) with two overlapping button to show the image is liked or disliked, and I need to do something when I click them, but I found that the item won't be selected if I just click the button, this makes I cannot get the item of the button which i clicked
I've try to google it but there's no help, all answers I got need to get the selecteditem at first, but this is where the question is
this is my data template
<DataTemplate DataType="model:PictureViewModel">
<Grid x:Name="ImageContentPresenter" Width="150" Height="150">
<Border x:Name="Border1" CornerRadius="15" Background="#FAFAFC" />
<Grid Height="150" Width="150">
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=Border1}" />
</Grid.OpacityMask>
<Border Background="#FAFAFC" x:Name="ImageCornerBorder"
CornerRadius="15,15,15,15" />
<Image x:Name="DisplayedImage" Stretch="Uniform"
Source="{Binding Path=ImageSource,Mode=OneWay,Converter={StaticResource BitmapImageConverter}}"
Loaded="DisplayedImage_OnLoaded">
<Image.OpacityMask>
<VisualBrush Visual="{Binding ElementName=ImageCornerBorder}" />
</Image.OpacityMask>
</Image>
<Grid HorizontalAlignment="Right" VerticalAlignment="Top" Width="30"
Height="30" Margin="0,10,10,0">
<Grid.Resources>
<util1:VisibilityConverter x:Key="VisibilityConverter" />
<mainWindow:ButtonType x:Key="LikeButtonType">Like</mainWindow:ButtonType>
<mainWindow:ButtonType x:Key="DisLikeButtonType">DisLike</mainWindow:ButtonType>
</Grid.Resources>
<Button x:Name="LikeButton" Style="{DynamicResource MaterialDesignToolButton}" Visibility="{Binding IsLiked,Converter={StaticResource VisibilityConverter},ConverterParameter={StaticResource LikeButtonType}}" Click="LikeButton_OnClick">
<Viewbox Width="24" Height="24">
<Canvas Width="24" Height="24">
<Path
Data="M12.1,18.55L12,18.65L11.89,18.55C7.14,14.24 4,11.39 4,8.5C4,6.5 5.5,5 7.5,5C9.04,5 10.54,6 11.07,7.36H12.93C13.46,6 14.96,5 16.5,5C18.5,5 20,6.5 20,8.5C20,11.39 16.86,14.24 12.1,18.55M16.5,3C14.76,3 13.09,3.81 12,5.08C10.91,3.81 9.24,3 7.5,3C4.42,3 2,5.41 2,8.5C2,12.27 5.4,15.36 10.55,20.03L12,21.35L13.45,20.03C18.6,15.36 22,12.27 22,8.5C22,5.41 19.58,3 16.5,3Z"
Fill="Gray" />
</Canvas>
</Viewbox>
</Button>
<Button x:Name="DislikeButton" Style="{DynamicResource MaterialDesignToolButton}" Visibility="{Binding IsLiked,Converter={StaticResource VisibilityConverter},ConverterParameter={StaticResource DisLikeButtonType}}">
<Viewbox Width="24" Height="24">
<Canvas Width="24" Height="24">
<Path
Data="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"
Fill="Crimson" />
</Canvas>
</Viewbox>
</Button>
</Grid>
</Grid>
</Grid>
</DataTemplate>
the LikeButton and DislikeButton are those two buttons, how exactly can I get the item where i clicked button is
You could access PictureViewModel object by accessing the DataContext property on the Button object in your LikeButton_OnClick method.
The ideal way would be to use Commands. You could have LikeCommand defined on the PictureViewModel itself and access it via this from the Command Handler.

WPF: How to access element in ResourceDictionary code behind

In my application I have a control which renders a number of blocks on a timeline view (like a calendar). One can provide a template for the blocks by giving the timeline an appropriate DataTemplate.
I would like to separate the block DataTemplate from the main timeline view, putting the block into its own XAML. As such, I've created a XAML for the Block (called Block.xaml) and wrapped the DataTemplate inside a ResourceDictionary, inside this XAML.
I've added a code behind to the XAML (called Block.xaml.cs) in which I need to access some of the elements in the block. The issue is that ResourceDictionaries seem to hide the elements from the codebehind such that I can't access them. I can't use a UserControl instead - this seems to not work.
How can I access the elements of the Block DataTemplate from the code behind?
Many thanks in advance for your help.
Block.xaml:
<ResourceDictionary x:Class="Project.Windows.MainInterface.TimelinePanel.Block" 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:local="clr-namespace:Project.Windows.MainInterface.TimelinePanel" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:converters="clr-namespace:Project.Converters" >
<DataTemplate x:Key="ItemBlockTemplate">
<Grid Name="BlockParent" Width="Auto" Height="Auto" MinHeight="50" ClipToBounds="True" SizeChanged="BlockParent_OnSizeChanged">
<Border Panel.ZIndex="3" BorderBrush="{DynamicResource BackgroundGreyLight}" BorderThickness="1" CornerRadius="1" />
<Grid Margin="1" Background="{DynamicResource BlockBackgroundGradient}" d:LayoutOverrides="Width">
<TextBlock x:Name="blockName" Height="20" Margin="4,0,4,0" Padding="3" VerticalAlignment="Top" Panel.ZIndex="3" FontSize="10" Foreground="{DynamicResource TextLight}" Text="{Binding blockName}" TextTrimming="CharacterEllipsis" Visibility="Visible" />
<TextBlock x:Name="Duration" Margin="0,2,4,2" Padding="0,0,3,0" HorizontalAlignment="Right" VerticalAlignment="Bottom" Panel.ZIndex="5" FontSize="10" Foreground="{DynamicResource TextLight}" Text="{Binding FormattedDuration}" ToolTip="{Binding Duration}" />
<Grid Background="#FF0FA8FF" Opacity="0.7" />
</Grid>
</Grid>
</DataTemplate>
Snippet of the Timeline in the main interface:
...
<timeLineTool:TimeLineControl x:Name="Timeline" Height="50" MinWidth="50" Margin="0,0,12,0" HorizontalAlignment="Left" VerticalAlignment="Top" Items="{Binding Timeline}" SnapsToDevicePixels="True" UnitSize="{Binding UnitSize}" UseLayoutRounding="True">
<timeLineTool:TimeLineControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:BlockItemViewModel}">
<ContentControl>
<ContentPresenter Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="{Binding}" ContentTemplate="{StaticResource ItemBlockTemplate}" />
</ContentControl>
</DataTemplate>
</timeLineTool:TimeLineControl.ItemTemplate>
</timeLineTool:TimeLineControl>
...
...If I could use a UserControl instead of a ResourceDictionary for my Block, this would solve the problem, as all elements are automatically publicly available in the code behind for usercontrols.
Sample XAML:
<Window.Resources>
<ControlTemplate x:Key="ResourceName" TargetType="{x:Type Label}">
<Label Foreground="White" Content="{iconPacks:PackIconFontAwesome plug,Height=40,Width=40}"/>
</ControlTemplate>
</Window.Resources>
Code behind
ControlTemplate Dictionary:
private Dictionary<string, ControlTemplate> collection
{
get
{
Dictionary<string, ControlTemplate> controlTemplates = new Dictionary<string, ControlTemplate>();
controlTemplates.Add("ResourceName", FindResource("ResourceName") as ControlTemplate);
return controlTemplates;
}
}
Use ControlTemplate:
Label LBDisConnect = new Label();
LBDisConnect.Template = collection["ResourceName"];
LoginInfo.Children.Add(LBDisConnect);

ScrollViewer not working with MouseWheel on GroupBox

I am trying to get a scrollviewer to work in a custom styled groupbox.
This is the style for the groupbox:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--Set default style of groupbox-->
<Style TargetType="GroupBox">
<Setter Property="Margin" Value="0, 10, 0, 0"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupBox">
<Border CornerRadius="4" BorderThickness="1" BorderBrush="{StaticResource BorderBrush}" Background="{StaticResource ContentBackgroundBrush}">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical" CanVerticallyScroll="True">
<Label Content="{TemplateBinding Header}" Margin="5,5,0,0" Style="{StaticResource SmallTitle}"></Label>
<ContentPresenter Margin="10, 5, 10, 10" RecognizesAccessKey="True" x:Name="CtlGroupboxPresenter" />
</StackPanel>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The scrollbar shows up, but I can't scroll using the mouse wheel. It works however when my mouse if over the vertical scrollbar. It seems like a tracking issue.
I saw some guys on SO that suggest adding some code to code behind to get it working, but as this is in a resource dictionary I have no place where I could put it...
Does anyone know what the issue is?
Here is an image of the wpf form:
XAML inside the groupbox:
<UserControl x:Class="Sun.Plasma.Controls.ViewNews"
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">
<DockPanel LastChildFill="True">
<Label DockPanel.Dock="Top" Style="{StaticResource LblTitle}" FontWeight="Bold" FontSize="24" >Latest SUN news & announcements</Label>
<StackPanel Orientation="Vertical" VerticalAlignment="Stretch">
<StackPanel Orientation="Vertical" Name="CtlLoadingNews">
<Label Style="{StaticResource LblContent}">Loading content from server...</Label>
<ProgressBar IsIndeterminate="True" Height="30" />
</StackPanel>
<ListView Background="Transparent" DockPanel.Dock="Bottom" ItemsSource="{Binding NewsFeeds}" BorderBrush="Transparent" Name="CtlNews" Visibility="Collapsed">
<!-- Defining these resources prevents the items from appearing as selectable -->
<ListView.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="0 0 0 20">
<Label Style="{StaticResource LblTitle}" FontWeight="Bold" Content="{Binding Title}" />
<StackPanel Orientation="Horizontal">
<Label Style="{StaticResource LblFooter}" Content="{Binding PublishDate}" />
<Label Style="{StaticResource LblFooter}">By</Label>
<Label Style="{StaticResource LblFooter}" Content="{Binding Authors[0]}" />
<Label Style="{StaticResource LblFooter}">
<Hyperlink RequestNavigate="Hyperlink_RequestNavigate" NavigateUri="{Binding Source}">Read entry</Hyperlink>
</Label>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DockPanel>
The problem is that the ListView in the contents of the GroupBox stops the MouseWheel event from bubbling up to the ScrollViewer. I found a hacky solution:
You handle the PreviewMouseWheel event on the inner ListView and raise the MouseWheel event directly on the scroll viewer.
private void ListView_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (!e.Handled)
{
e.Handled = true;
var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
eventArg.RoutedEvent = UIElement.MouseWheelEvent;
eventArg.Source = sender;
//navigate to the containing scrollbar and raise the MouseWheel event
(((sender as ListView).Parent as GroupBox).Content as ListView).RaiseEvent(eventArg);
}
}
Again, this is not a solution I particularly like, because it is dependent on the layout of the GroupBox.
A second, slightly better way is to add a style to the resources of the GroupBox in which you add a handler to the PreviewMouseWheel event:
<GroupBox Header="test">
<GroupBox.Resources>
<Style TargetType="ScrollViewer">
<EventSetter Event="PreviewMouseWheel" Handler="ScrollViewer_PreviewMouseWheel" />
</Style>
</GroupBox.Resources>
<!-- your contents -->
</GroupBox>
The event handler then does the scrolling:
private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var scrollViewer = sender as ScrollViewer;
double change = e.Delta;
double currentPosition = scrollViewer.VerticalOffset;
scrollViewer.ScrollToVerticalOffset(currentPosition - change);
}

Categories

Resources