I have a windows phone project(WPF) in which I use a Slider control for changing the volume of a media. The slider was working perfectly, but I had to customize the slider as per the project design. So I customized it, but after customisation the slider no longer works. It doesn't show the binded value, it doesn't seek(even though the binded functions for tap and manipulation are trigerred as it should). In short, after customization it appears like a static user control with no action.
Following is the code written in App.xaml to customize the slider:
<ControlTemplate x:Key="PhoneSimpleRepeatButton" TargetType="RepeatButton">
<Rectangle Fill="Transparent"/>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbTemplate" TargetType="Thumb">
<Image x:Name="ThumbImage" Source="ms-appx:///Images/PlayList/slider_knob.png" />
</ControlTemplate>
<Style x:Key="VolumeControlSliderStyle" TargetType="Slider">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Slider">
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="0"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle x:Name="VerticalTrack" Fill="#7b5798" IsHitTestVisible="True" Margin="12,0" Grid.RowSpan="3" Width="17" RadiusX="5" RadiusY="5"/>
<Rectangle x:Name="VerticalFill" Fill="#b09bc1" IsHitTestVisible="True" Margin="12,9" Grid.Row="2" Width="5"/>
<RepeatButton x:Name="VerticalTrackLargeChangeDecreaseRepeatButton" IsTabStop="False" Grid.Row="0" Template="{StaticResource PhoneSimpleRepeatButton}" MinWidth="0"/>
<RepeatButton x:Name="VerticalTrackLargeChangeIncreaseRepeatButton" IsTabStop="False" Grid.Row="2" Template="{StaticResource PhoneSimpleRepeatButton}" MinWidth="0"/>
<Thumb x:Name="VerticalThumb" Height="1" Margin="0,-1,0,0" RenderTransformOrigin="0.5,0.5" Grid.Row="1" Template="{StaticResource SliderThumbTemplate}">
<Thumb.RenderTransform>
<ScaleTransform ScaleY="20" ScaleX="20"/>
</Thumb.RenderTransform>
</Thumb>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--Slider Style Ends-->
Following is the code in the UI XAML that declares the slider:
<Slider
Minimum="0"
Maximum="100"
Style="{StaticResource VolumeControlSliderStyle}"
Value="{Binding Source={StaticResource Locator}, Path=MusicPlaylist.Volume, Mode=TwoWay}"
ManipulationMode="All"
HorizontalAlignment="Center"
ManipulationStarted="VolumeChanged"
ManipulationDelta="VolumeChanged"
ManipulationCompleted="VolumeChanged"
Tapped="VolumeChanged"
Orientation="Vertical"
Margin="0,10,0,0"
Height="150" />
It was all working fine till customization, but after customization the slider simply stays idle, it doesn't change value, doesn't seek and do nothing. However if I remove the Style, it simple works again, which makes me think the problem is with the style code(in XAML). But I can't determine what. Please help.
EDIT
I followed this tutorial for customization.
I think you have to modify the different parts of the track to get it to work as normal.
There are a few code examples on this post that could help.
I used Blend for Visual Studio to create a custom slider and discarded the above code. That solved the issue.
Related
To reproduce this, simply add this style to any wpf project that has a RichTextBox:
https://pastebin.com/dJAqFC3d
And a full minimal project can be located here:
https://drive.google.com/file/d/1a7e-vwKpt1Emg7fhMhVRLccwrjOlhWk1/view?usp=sharing
Also an example of the two styles:
<!--
This style does NOT break RichTextBox Scrolling
-->
<Style TargetType="{x:Type ScrollViewer}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</Style.Resources>
</Style>
<!--
The Style below breaks Rich Text Box
-->
<!--<Style TargetType="{x:Type ScrollViewer}">
<Setter Property="CanContentScroll" Value="True"></Setter>
<Setter Property="PanningMode" Value="Both"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollContentPresenter Grid.Column="0" />
<ScrollBar
x:Name="PART_VerticalScrollBar"
Grid.Row="0"
Grid.Column="1"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Value="{TemplateBinding VerticalOffset}" />
<ScrollBar
x:Name="PART_HorizontalScrollBar"
Grid.Row="1"
Grid.Column="0"
Maximum="{TemplateBinding ScrollableWidth}"
Orientation="Horizontal"
ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
Value="{TemplateBinding HorizontalOffset}" />
--><!--<Rectangle Grid.Row="1" Grid.Column="1" Fill="Red"/>--><!--
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>-->
Then at the bottom of the style, comment out either of the ScrollViewer styles to swap between them. One simply overrides the bottom right rectangle color. The other does the same, but also defines the scrollbars. The style that defines the scrollbars breaks vertical scrolling.
This can also be reproduced using the official Microsoft provided styles, located here:
https://learn.microsoft.com/en-us/dotnet/desktop/wpf/controls/scrollbar-styles-and-templates?view=netframeworkdesktop-4.8
and here
https://learn.microsoft.com/en-us/dotnet/desktop/wpf/controls/scrollviewer-styles-and-templates?view=netframeworkdesktop-4.8
UPDATE: (The above links will soon be an invalid example, because this issue has been submitted, and it is apparently going to be addressed and fixed)
Does anyone know why declaring a custom style for ScrollViewers breaks RichTextBox mouse wheel scrolling?
Edit: It should also be noted that the above example does not hinder or break the vertical mouse wheel scrolling of any other control (that I've noticed). RichTextBox seems to be an edge case.
Found the solution, and it's actually stupid easy.
You have to add CanContentScroll="True" to the ScrollContentPresenter within the ScrollViewer control template. Here is an example:
<Style TargetType="{x:Type ScrollViewer}">
<Setter Property="CanContentScroll" Value="True"></Setter>
<Setter Property="PanningMode" Value="Both"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollContentPresenter CanContentScroll="True" Grid.Column="0" />
<ScrollBar
x:Name="PART_VerticalScrollBar"
Grid.Row="0"
Grid.Column="1"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Value="{TemplateBinding VerticalOffset}" />
<ScrollBar
x:Name="PART_HorizontalScrollBar"
Grid.Row="1"
Grid.Column="0"
Maximum="{TemplateBinding ScrollableWidth}"
Orientation="Horizontal"
ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
Value="{TemplateBinding HorizontalOffset}" />
<Rectangle Grid.Row="1" Grid.Column="1" Fill="Red"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This is not mentioned anywhere within the microsoft style example, and they also ommit it from their suggested style template.
I am having an issue with the Microsoft WPF ProgressBar. I will set Width="Auto" and the width will size to the text width until a value property of ~97. Between values 97 and 100 the control will go exponentially larger until it hits MaxWidth.
The following style is setting the template for the ProgressBar. I can't seem to find anything that will cause it to behave until a Value of ~97. I do not touch the width in the code behind.
<Style x:Key="CurrentDayProgressBar" TargetType="{x:Type ProgressBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid>
<Border Name="PART_Track" CornerRadius="2" Background="DarkGray" BorderBrush="{DynamicResource TextBrush}" BorderThickness="1" />
<Border Name="PART_Indicator" CornerRadius="2" Background="{DynamicResource ProgressBarBackground}" HorizontalAlignment="Left" Margin="2" />
<TextBlock Name="PART_Text" Margin="2" Width="Auto" Padding="5,0,5,0" Text="{Binding RelativeSource={RelativeSource AncestorType=ProgressBar}, Path=Tag}"
Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{DynamicResource SimpleTextBlock}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The first image below is what the bar looks like when it is at a Value of 99.2. The second is my implementation in the Telerik RadProgressBar, which behaves like I expect it to. The Telerik solution may be what I have to go with, but it would be nice to know why the Microsoft control is not working.
WPF ProgressBar Control
Telerik RadProgressBar and Textbox
The PART_Track cannot have any extra margins/borders attached to it and/or the PART_Indicator should be nested inside it. To resolve the problem you're having, do something like:
<Border CornerRadius="2" Background="DarkGray" BorderBrush="{DynamicResource TextBrush}" BorderThickness="1" />
<Border x:Name="PART_Track" Margin="3">
<Border Name="PART_Indicator" CornerRadius="2" Background="{DynamicResource ProgressBarBackground}" HorizontalAlignment="Left" />
</Border>
<TextBlock ... />
It seems that there should be a very easy solution to this but I cannot find it and it's killing me ...
All I wanna do is to add a right aligned refresh button (or image, or whatever) to the Header of a PanaromaItem in a Panorama, so pressing it reloads the data. (look at the image below)
I tried overriding the PanoramaItem.Header:
<phone:PanoramaItem.Header>
<Grid>
<TextBlock Text="first item" />
<Image source="blah" HorizontalAlignment="Right" />
</Grid>
</phone:PanoramaItem.Header>
and I tried using Grid, StackPanel, ViewPanel and every other layout controller that I knew and couldn't achieve this unless I set a constant width.
Any idea?
Might as well answer this one correctly, just incase someone needs it.
You need to override the PanoramaItemStyle and set the Header ContentControl to Stretch.
HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch"
That way when you apply the template it will cover the whole width. Here is the full Override Style Template.
<phone:PhoneApplicationPage.Resources>
<Style x:Key="Chubs_PanoramaItemStyle" TargetType="phone:PanoramaItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="phone:PanoramaItem">
<Grid Background="{TemplateBinding Background}" Margin="12,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentControl x:Name="header" CharacterSpacing="-35" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" FontSize="66" FontFamily="{StaticResource PhoneFontFamilySemiLight}" Margin="12,-2,0,38" HorizontalContentAlignment="Stretch">
<ContentControl.RenderTransform>
<TranslateTransform x:Name="headerTransform"/>
</ContentControl.RenderTransform>
</ContentControl>
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Grid.Row="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</phone:PhoneApplicationPage.Resources>
Now apply that style to the PanoramaItem like so
<phone:PanoramaItem Style="{StaticResource Chubs_PanoramaItemStyle}">
<phone:PanoramaItem.Header>
<Grid>
<TextBlock Text="header1"/>
<Image Source="/Assets/ApplicationIcon.png" Stretch="None" HorizontalAlignment="Right"></Image>
</Grid>
</phone:PanoramaItem.Header>
</phone:PanoramaItem>
And Screenshot of the results:
By default when we set horizontal alignment to the image within panorama item header then it is not working But we can fix the width of the header textblock and set the alignment right for the image.
<controls:PanoramaItem.Header>
<Grid>
<TextBlock Text="First" Width="400"/>
<Image Source="/ApplicationIcon.png" Width="60" Height="60" HorizontalAlignment="Right" />
</Grid>
</controls:PanoramaItem.Header>
I tried horizontalalign="Right" is not working but to achive this you could set left margin:
<phone:PanoramaItem Header="My Books" Foreground="LightGray" Margin="-10,0,0,0">
<phone:PanoramaItem.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="#72C158" Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}" Margin="0,30,0,0" FontSize="55" FontFamily="/Font/BKANT.TTF#Book Antiqua" TextAlignment="Left" FontWeight="Normal"/>
<Button Height="50" Width="50" Margin="130,20,0,0"/>
</StackPanel>
</DataTemplate>
</phone:PanoramaItem.HeaderTemplate>
</phone:PanoramaItem>
As described here, you will need to override the pivotitem template to set the HorizontalAlignment of the Header to Stretch.
After that you should be able to align stuff to the right of the header.
I created a control template for all TabControl in my application. The template places the TabPanel at the left of the tab item's main content.
<Style TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TabPanel Grid.Column="0"
Panel.ZIndex="1"
Margin="0,0,0,0"
IsItemsHost="True"
Background="Transparent" />
<Border Grid.Column="1"
BorderBrush="Black"
BorderThickness="1"
CornerRadius="0,12,12,12">
<Border.Background>
<SolidColorBrush Color="Green" />
</Border.Background>
<ContentPresenter ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This is initially what I want my tab controls to look like. But when I set the TabStripPlacement property to Top, it still stays in the left side. Is there a way to define in the control template to adjust the position of TabPanel based on the TabStrip property? Thanks in advanced.
You need to use triggers in your style that react to the change in the TabStripPlacement property.
This stackoverflow post provides an example of this.
I have a scrolling TabControl, using a ScrollViewer and StackPanel (with the StackPanel set as IsItemsHost="true"). To begin with, I am working from a solution originally outlined here - Creating Scrolling Tabs Using WPF's TabControl . At the moment it has broken links (Edit: I have tracked down one instance of his code in a forum here - How to prevent TabControl from doing multi rows?), so here is the xaml for the TabControl (does not require any further code):
<TabControl x:Name="TabControl2" Height="Auto" TabStripPlacement="Bottom" VerticalAlignment="Bottom" Template="{DynamicResource TabControlControlTemplate1}" IsSynchronizedWithCurrentItem="True">
<TabControl.Resources>
<Style x:Key="TabScrollerRepeatButtonStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" Margin="1,0">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding ContentControl.Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="TabControlControlTemplate1" TargetType="{x:Type TabControl}">
<Grid x:Name="Grid" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0"/>
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
<RowDefinition x:Name="RowDefinition1" Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="1" Grid.Column="0" x:Name="ContentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0,1,1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.DirectionalNavigation="Contained">
<Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Border Background="{TemplateBinding Background}" x:Name="Border1">
<ContentPresenter DataContext="{x:Null}" Margin="{TemplateBinding Padding}" x:Name="PART_SelectedContentHost" Content="{TemplateBinding SelectedContent}" ContentTemplate="{TemplateBinding SelectedContentTemplate}" ContentTemplateSelector="{TemplateBinding SelectedContentTemplateSelector}" ContentSource="SelectedContent"/>
</Border>
</Border>
</Border>
<ScrollViewer x:Name="HeaderPanel" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
<ScrollViewer.Style>
<Style TargetType="{x:Type ScrollViewer}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Margin="0,0,0,0" Grid.Row="0" Grid.Column="0" x:Name="HeaderPanel">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<RepeatButton Grid.Column="1" Content="<" Command="ScrollBar.LineLeftCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}" Visibility="{Binding Path=ComputedHorizontalScrollBarVisibility, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
<ScrollContentPresenter Grid.Column="2" Content="{TemplateBinding ScrollViewer.Content}" />
<RepeatButton Grid.Column="3" Content=">" Command="ScrollBar.LineRightCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}" Visibility="{Binding Path=ComputedHorizontalScrollBarVisibility, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ScrollViewer.Style>
<StackPanel IsItemsHost="true" Orientation="Horizontal" Background="{x:Null}" KeyboardNavigation.TabIndex="1"/>
</ScrollViewer>
</Grid>
</ControlTemplate>
</TabControl.Resources>
<TabItem x:Name="TabItem1" Header="TabItem1"/>
<TabItem x:Name="TabItem2" Header="TabItem2"/>
</TabControl>
How might I adjust the appearance of each TabItem? For instance, I would like to place a TextBox and TextBlock inside each TabItem, with the help of a StackPanel, so that I can have renameable tabs (collapsing one or the other as appropriate). I might also want to add a close button on each tab. Ordinarily, I would use something like the following:
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Name="panel" Orientation="Horizontal">
<TextBox Name="editHeader" Text="{Binding Header}" MaxWidth="250"/>
<TextBlock Name="textHeader" Text="{Binding Header}" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
.. but this is having no effect at all. Any ideas would be appreciated. Thanks.
Edit: I am still trying to figure this out. Is it possible that the solution could involve ContentPresenter and/or SelectedContentTemplate?
Edit 2: (this doesn't add value to my question) I really, really wish WPF included something of this sort out of the box. I am baffled by TabControl's default behavior, and by the fact that there is no scrollable TabControl (nor simple solution for attaining one) after some years.
Hey guesser. I've done something similar, I based mine off of this series though
http://www.blogs.intuidev.com/post/2010/post/2010/01/25/TabControlStyling_PartOne.aspx
The method used is to simply style the tabitems template. eg:
<TabControl.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<!-- your custom template goes here -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
Unforunately this method means you will have to completely redefine the way the tab items look and behave. But the provided link gives good examples on how achieve this.
Hope it helps.
Just a thought,
have you tried just adding the text block to the TabItem.Header? If you do this instead of a template it might work. Has for me in the past
I think I've got it (though still crossing fingers a bit -- I haven't yet dealt with Visibility of the TextBlock vs TextBox for renaming).
It is similar to Val's solution in that I'm working in TabControl.Resources on its TabItem, but the Property concerned is HeaderTemplate and I just override the ContentPresenter in a DataTemplate. (measures to avoid replacing\destroying a lot of good behavior that comes for free with the TabControl)
<TabControl.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<ContentPresenter>
<ContentPresenter.Content>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{TemplateBinding Content}"/>
<TextBox Text="{TemplateBinding Content}"/>
</StackPanel>
</ContentPresenter.Content>
</ContentPresenter>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
I'm somewhat of a WPF newb, so this is basically a result of persistent experimentation with what I could find Googling. For those interested, this link (on StackOverflow) helped me most in the end - WPF TabItem Header Styling