How to implement AutoScroll HeaderedItemsControl WPF? - c#

I merged the things I have found out to implement an auto-scroll-to-end Headered Items Control. I cannot manage to do it. What am I doing wrong?
In Resource Directory, ScrollingHeaderedItemsControl is styled as:
<Style TargetType="common:ScrollingHeaderedItemsControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="3" SnapsToDevicePixels="True">
<StackPanel>
<Grid>
<Rectangle Fill="{TemplateBinding Background}"/>
<ContentPresenter ContentSource="Header" Margin="2,0,0,0"/>
</Grid>
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<ItemsPresenter Margin="5,0,0,0"/>
</ScrollViewer>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The class ScrollingHeaderedItemsControl is defined as here:
public class ScrollingHeaderedItemsControl : HeaderedItemsControl
{
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
int newItemCount = e.NewItems.Count;
if (newItemCount > 0)
this.ScrollToEnd();
base.OnItemsChanged(e);
}
}
}
ScrollToEnd is a static function written specifically for ScrollingHeaderedItemsControl such as:
public static void ScrollToEnd(this ItemsControl control)
{
try
{
Border border = VisualTreeHelper.GetChild((DependencyObject)control, 0) as Border;
StackPanel sp = VisualTreeHelper.GetChild((DependencyObject)border, 0) as StackPanel;
ScrollViewer sv = VisualTreeHelper.GetChild((DependencyObject)sp, 1) as ScrollViewer;
sv.ScrollToEnd();
}
catch(Exception)
{
}
}
ScrollingHeaderedItemsControl is used in the UserControl like this:
<common:ScrollingHeaderedItemsControl x:Name="MessagesHIC" FontSize="32" Header="Error/Warning/Info Messages"
Background="Green"
BorderBrush="AntiqueWhite" ItemsSource="{Binding Messages}"
Margin="10" Grid.Row="1" Grid.Column="0"
ScrollViewer.CanContentScroll="True">
<common:ScrollingHeaderedItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding MessageString}" Foreground="{Binding MessageColor}" TextWrapping="Wrap" FontWeight="Light" FontSize="26" />
</DataTemplate>
</common:ScrollingHeaderedItemsControl.ItemTemplate
</common:ScrollingHeaderedItemsControl>

Your template contains a stackpanel which doesn't set a height constraint, therefore the scrollviewer is never required to show the scrollbars. Change your Template to the following:
<Style TargetType="common:ScrollingHeaderedItemsControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="3" SnapsToDevicePixels="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid>
<Rectangle Fill="{TemplateBinding Background}" />
<ContentPresenter ContentSource="Header" Margin="2,0,0,0" />
</Grid>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Hidden">
<ItemsPresenter Margin="5,0,0,0" />
</ScrollViewer>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You will then need to change your code behind to:
try
{
Border border = VisualTreeHelper.GetChild((DependencyObject)control, 0) as Border;
Grid sp = VisualTreeHelper.GetChild((DependencyObject)border, 0) as Grid;
ScrollViewer sv = VisualTreeHelper.GetChild((DependencyObject)sp, 1) as ScrollViewer;
sv.ScrollToEnd();
}
catch (Exception)
{
}

Related

LiveCharts ColumnSeries not showing

I'm using LiveCharts in WPF to visualize the results of some analyses. The results of an analysis is added to a SeriesCollection and displayed in an CartesianChart. You can choose which type of series to use: LineSeries or ColumnSeries. The chosen type is then created and added to the SeriesCollection.
There's a custom mapper for selecting X and Y values from the ChartValues and a AxisFormatter for the X axis.
The charts are part of an Blacklight.Controls.Wpf.DragDockPanelHost. Each chart is an DragDockPanel with a style attached to it. The chart itself is a ContentControl with an TemplateSelector that returns the CartesianChart-XAML as a DataTemplate.
I've already tried to set the Fill or Stroke of the series or putting some ColumnSeries in there manually but that didn't help at all.
Filling of the SeriesCollection:
private SeriesCollection _Series;
public SeriesCollection Series
{
get { return _Series; }
set { SetProperty<SeriesCollection>(ref _Series, value); }
}
...
private void createDiagram()
{
if (this._Analysis!= null && this._Diagram != null)
{
this.Series.Clear();
foreach (KeyValuePair<state, Dictionary<DateTime, int>> kvp in this.Analysis.Execute())
{
Series series = Activator.CreateInstance(Diagram) as Series;
if (series != null)
{
series.Title = kvp.Key.name;
series.Values = new ChartValues<KeyValuePair<DateTime, int>>(kvp.Value);
this.Serien.Add(series);
}
}
}
}
Mapper and AxisFormatter:
CartesianMapper<KeyValuePair<DateTime, int>> mapper = Mappers.Xy<KeyValuePair<DateTime, int>>().X(kvp => ((DateTimeOffset)kvp.Key).ToUnixTimeSeconds()).Y(kvp => kvp.Value);
this.Series = new SeriesCollection(mapper);
this.XFormatter = value =>
{
return DateTimeOffset.FromUnixTimeSeconds((long)value).DateTime.ToString("dd.MM.yyyy HH:mm");
};
TemplateSelector:
public class DashboardElementTemplateSelector : DataTemplateSelector
{
public DataTemplate ListDashboardElementTemplate { get; set; }
public DataTemplate SingleValueDashboardElementTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is ListDashboardElementViewModel)
return this.ListDashboardElementTemplate;
else
return this.SingleValueDashboardElementTemplate;
}
}
XAML of DragDockPanelHost:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<DataTemplate x:Key="listElement">
<views:ListDashboardElementView/>
</DataTemplate>
<DataTemplate x:Key="singleValueElement">
<views:SingleValueDashboardElementView/>
</DataTemplate>
<tempselect:DashboardElementTemplateSelector x:Key="elementTempSelector"
ListDashboardElementTemplate="{StaticResource listElement}"
SingleValueDashboardElementTemplate="{StaticResource singleValueElement}"
/>
</ResourceDictionary>
<ResourceDictionary>
<conv:BooleanToVisibilityConverter x:Key="visCon"/>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<bl:DragDockPanelHost ItemsSource="{Binding Diagrams}" Grid.Row="1" Margin="20" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<bl:DragDockPanelHost.Style>
<Style TargetType="bl:DragDockPanelHost">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Canvas ClipToBounds="True" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
</Canvas>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="bl:DragDockPanelHost">
<ItemsPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</bl:DragDockPanelHost.Style>
<bl:DragDockPanelHost.DefaultPanelStyle>
<Style TargetType="{x:Type bl:DragDockPanel}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Margin="10">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Background="#00000000" Margin="-2" Padding="5" Grid.Row="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<WrapPanel>
<Image Width="20" x:Name="GripBarElement" Source="/Aisys.XStorage.Dashboard;component/Images/move.png" Grid.Column="0" Cursor="Hand" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding Name}" Grid.Column="0" FontSize="16" FontWeight="Bold" Margin="10,0,0,0"/>
</WrapPanel>
<WrapPanel HorizontalAlignment="Right" Grid.Column="2">
<Button Command="{Binding ExecuteCommand}" CommandParameter="{Binding}" Margin="5,0,5,0">
<Button.Template>
<ControlTemplate>
<Image Source="/Aisys.XStorage.Dashboard;component/Images/Refresh.png"/>
</ControlTemplate>
</Button.Template>
</Button>
<Button Width="20" Command="{Binding DataContext.RemoveDiagramCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type bl:DragDockPanelHost}}}" CommandParameter="{Binding}">
<Button.Template>
<ControlTemplate>
<Image Source="/Aisys.XStorage.Dashboard;component/Images/Remove.png"/>
</ControlTemplate>
</Button.Template>
</Button>
<Button Command="{Binding DataContext.ShowPropertiesCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type bl:DragDockPanelHost}}}" CommandParameter="{Binding}" Margin="5,0,5,0">
<Button.Template>
<ControlTemplate>
<Image Source="/Aisys.XStorage.Dashboard;component/Images/Preferences.png"/>
</ControlTemplate>
</Button.Template>
</Button>
<ToggleButton x:Name="MaximizeToggleButton" VerticalAlignment="Top" HorizontalAlignment="Right" IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, Path=IsMaximized}" Margin="0,5,5,0" Width="25" Height="25" Cursor="Hand">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Image Source="/Aisys.XStorage.Dashboard;component/Images/Maximize.png" Margin="0,0,0,5"/>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</WrapPanel>
</Grid>
</Border>
<Separator VerticalAlignment="Bottom" Margin="0,0,0,0"/>
<ContentControl Content="{Binding}" ContentTemplateSelector="{StaticResource elementTempSelector}" Grid.Row="1" Margin="10"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</bl:DragDockPanelHost.DefaultPanelStyle>
</bl:DragDockPanelHost>
XAML of chart:
<Grid>
<lvc:CartesianChart Series="{Binding Series}" LegendLocation="Right" Name="chart">
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="Zeit" LabelFormatter="{Binding XFormatter}">
</lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</Grid>
If I'm choosing LineSeries, everything works fine. But when I'm using ColumnSeries nothing is shown. You can see, that the axis is redrawn and the separators move. The legend is also drawn, but there are no columns visible.
Any ideas why this is happening?
I had the same problem recently. Unfortunately, this doesn't seem to be documented anywhere but for some reason if you have too many data points for the size of the graph, then none of the columns will display. You can either try reducing the number of data points until it works (in my case 90 data points wouldn't display, but 30 would), or on ColumnSeries there is a property ColumnPadding that you can turn down to zero and see if that helps.

How to Change the Color of Slider on Xamarin.Forms, on Android, iOs, UWP using custom renderers?

I have changed successfully the color of the Slider on Android creating a Custom Renderer Here the example.
[assembly: ExportRenderer(typeof(CustomSlider), typeof(CustomSliderRenderer))]
namespace ForteMultiplataform.Droid
{
public class CustomSliderRenderer : SliderRenderer
{
public CustomSliderRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
string colorSlider = "#008000";
Control.ProgressDrawable.SetColorFilter(Xamarin.Forms.Color.FromHex(colorSlider).ToAndroid(), PorterDuff.Mode.SrcIn);
// Set Progress bar Thumb color
Control.Thumb.SetColorFilter(
Xamarin.Forms.Color.FromHex(colorSlider).ToAndroid(),
PorterDuff.Mode.SrcIn);
}
}
}
}
How to achieve that for iOS, and UWP?
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
string colorSlider = "#008000";
//What do I put here??
}
}
iOS Custom Renderer
According to the Apple Docs, UISlider has three properties for which we'll need to update:
MaximumTrackTintColor
Specifies the tint color of the track to the leading side of the slider’s thumb. The value defaults to the slider’s inherited tint color. Access this value at runtime with the minimumTrackTintColor property.
MinimumTrackTintColor
Specifies the tint color of the track to the trailing side of the slider’s thumb. Access this value at runtime with the maximumTrackTintColor property.
ThumbTintColor
Controls the tint color of the slider’s thumb. Access this value at runtime with the thumbTintColor property
Code
[assembly: ExportRenderer(typeof(CustomSlider), typeof(CustomSliderRenderer))]
namespace CustomSliderColor.iOS
{
public class CustomSliderRenderer : SliderRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
{
base.OnElementChanged(e);
if (Control != null)
{
const string colorSlider = "#008000";
Control.MaximumTrackTintColor = Color.FromHex(colorSlider).ToUIColor();
Control.MinimumTrackTintColor = Color.FromHex(colorSlider).ToUIColor();
Control.ThumbTintColor = Color.FromHex(colorSlider).ToUIColor();
}
}
}
}
UWP Custom Renderer
In your App.xaml class you create your own Style for the Slider, Add an Application.Resources tag with your Slider Style
<Application
x:Class="ForteMultiplataform.UWP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ForteMultiplataform.UWP"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="styledSlider" TargetType="Slider">
<Setter Property="Background" Value="#0C720B"/>
<Setter Property="BorderBrush" Value="#129E11"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="Foreground" Value="#24DB23"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Slider">
<Grid Margin="{TemplateBinding Padding}">
<Grid.Resources>
<Style x:Key="SliderThumbStyle" TargetType="Thumb">
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="#0C720B"/>
<Setter Property="Foreground" Value="#129E11"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Ellipse StrokeThickness="2" Stroke="{TemplateBinding BorderBrush}" Fill="{TemplateBinding Foreground}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="SliderContainer" Background="Transparent" Grid.Row="1">
<Grid x:Name="HorizontalTemplate">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="17"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="17"/>
</Grid.RowDefinitions>
<Rectangle x:Name="HorizontalTrackRect" Grid.ColumnSpan="3" Fill="{TemplateBinding Background}" Grid.Row="1" Height="10" RadiusX="5" RadiusY="5"/>
<Rectangle x:Name="HorizontalDecreaseRect" Fill="{TemplateBinding Background}" Grid.Row="1" Height="10" RadiusX="5" RadiusY="5"/>
<Rectangle x:Name="HorizontalBorder" Grid.ColumnSpan="3" Grid.Row="1" Stroke="{TemplateBinding BorderBrush}"
StrokeThickness="{TemplateBinding BorderThickness}" Height="10" RadiusX="5" RadiusY="5"/>
<Thumb x:Name="HorizontalThumb" AutomationProperties.AccessibilityView="Raw" Background="{ThemeResource SliderThumbBackgroundThemeBrush}"
Grid.Column="1" DataContext="{TemplateBinding Value}" Grid.Row="1" Style="{StaticResource SliderThumbStyle}" Height="25" Width="25"/>
</Grid>
<Grid x:Name="VerticalTemplate" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="17"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="17"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle x:Name="VerticalTrackRect" Grid.Column="1" Fill="{TemplateBinding Background}" Grid.RowSpan="3" Width="10" RadiusX="5" RadiusY="5"/>
<Rectangle x:Name="VerticalDecreaseRect" Grid.Column="1" Fill="{TemplateBinding Background}" Grid.Row="2"/>
<Rectangle x:Name="VerticalBorder" Grid.RowSpan="3" Grid.Column="1" Stroke="{TemplateBinding BorderBrush}"
StrokeThickness="{TemplateBinding BorderThickness}" Width="10" RadiusX="5" RadiusY="5" />
<Thumb x:Name="VerticalThumb" AutomationProperties.AccessibilityView="Raw" Background="{ThemeResource SliderThumbBackgroundThemeBrush}"
Grid.Column="1" DataContext="{TemplateBinding Value}" Grid.Row="1" Style="{StaticResource SliderThumbStyle}" Height="15" Width="25"/>
</Grid>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
Then in your custom renderer load this style
[assembly: ExportRenderer(typeof(CustomSlider), typeof(CustomSliderRenderer))]
namespace ForteMultiplataform.UWP
{
public class CustomSliderRenderer : SliderRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Windows.UI.Xaml.Style sliderStyle = (Windows.UI.Xaml.Style)Windows.UI.Xaml.Application.Current.Resources["styledSlider"];
Control.Style = sliderStyle;
}
}
}
}
Track colors are also available directly in the Xamarin.Forms
Slider.MaximumTrackColor = Color.Red
Slider.MinimumTrackColor = Color.Green
Slider.ThumbColor = Color.Blu
They will be rendered in the different platforms accordingly.
I just realized that on Android is also possible to change the propery "colorAccent" on the "styles.xml" file of your Xamarin.Android project:
<item name="colorAccent">#008000</item>
This will also change the color of another GUI components like Switch for example.

Scrolling to active tabcontrol header in stackpanel in WPF

With the following code I can create a non wrapped scrolling stackpanel of headers of a tabcontrol. It has repeat buttons that can control the scroll. I would like instead for the repeat buttons to be able to control which tab is active, and adjust the scroll so the active tab can scroll into view. Is such a thing possible?
<TabControl SelectedItem="{Binding ActiveTicketFilterTab, Mode=TwoWay}"
Margin="5"
Grid.Row="1"
BorderBrush="Gray"
BorderThickness="2"
Style="{StaticResource ResourceKey=somestyle}"
SelectionChanged="selectionchanged"
Name="somename"
Background="#252525"
ItemsSource="{Binding someobslist}"
Grid.ColumnSpan="2">
<TabControl.Resources>
<Style x:Key="TabScrollerRepeatButtonStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Background="sc#1, 0.366693377, 0.372125238, 0.6931424">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding ContentControl.Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabControl.Template>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid ClipToBounds="true" SnapsToDevicePixels="true" 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>
<ScrollViewer Panel.ZIndex="1" 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="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollContentPresenter Grid.Column="0" Content="{TemplateBinding ScrollViewer.Content}" />
<StackPanel Orientation="Horizontal" Grid.Column="1">
<RepeatButton Style="{StaticResource TabScrollerRepeatButtonStyle}" Content="<" Command="ScrollBar.LineLeftCommand"/>
<RepeatButton Style="{StaticResource TabScrollerRepeatButtonStyle}" Content=">" Command="ScrollBar.LineRightCommand"/>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ScrollViewer.Style>
<StackPanel x:Name="HeaderPanel" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1" Orientation="Horizontal"/>
</ScrollViewer>
<Border x:Name="ContentPanel"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Grid.Row="1"
Grid.Column="0"
Margin="2,-2, 0, 13"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex="2"
KeyboardNavigation.TabNavigation="Local">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
</ControlTemplate>
</TabControl.Template>
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem" BasedOn="{StaticResource someotherstyle}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Border BorderBrush="{x:Null}" Height="25">
<TextBlock Padding="10" Name="Title" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" HorizontalAlignment="Stretch" Text="{Binding Name}" ToolTip="{Binding Name}" />
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.ItemContainerStyle>
<TabControl.ContentTemplate>
<DataTemplate>
<Grid Background="Transparent">
<ListBox x:Name="ticketView"
Unloaded="On_Listbox_enter"
ItemsSource="{Binding TicketsView}"
Background="#252525"
Margin="5,5,0,0"
HorizontalContentAlignment="Stretch"
BorderBrush="{x:Null}"
BorderThickness="1"
Padding="0,0,5,0"
VirtualizingPanel.IsVirtualizing="False"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="False"
ItemTemplate="{StaticResource TicketViewTemplate}">
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#252525" />
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="Transparent" />
</ListBox.Resources>
</ListBox>
<StackPanel Grid.Row="0" Margin="328,75"
Visibility="{Binding ExposeTicketSpinner, Converter={StaticResource BoolToVisConverter}}"
Width="Auto">
<Viewbox Grid.Row="0"
Height="100"
Width="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<WPFControls:CircularProgressBar HorizontalAlignment="Center" VerticalAlignment="Center" />
</Viewbox>
<Label Foreground="White" FontWeight="Bold" Margin="0,33" Content="Loading Tickets..." HorizontalAlignment="Center"></Label>
</StackPanel>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
To get your things to work as desired, do the following:
First
Replace your Repeatbuttons with this
<RepeatButton Style="{StaticResource TabScrollerRepeatButtonStyle}" Content="<" Command="{Binding MoveLeftCommand}"/>
<RepeatButton Style="{StaticResource TabScrollerRepeatButtonStyle}" Content=">" Command="{Binding MoveRightCommand}"/>
Second
In your ViewModel (That holds the TabControl) do it like this:
public ICommand MoveLeftCommand => new RelayCommand(x => {
var currIdx = this.someobslist.IndexOf(this.ActiveTicketFilterTab);
this.ActiveTicketFilterTab = currIdx == 0 ? this.someobslist[this.someobslist.Count - 1] : this.someobslist[currIdx - 1];
});
public ICommand MoveRightCommand => new RelayCommand(x => {
var currIdx = this.someobslist.IndexOf(this.ActiveTicketFilterTab);
this.ActiveTicketFilterTab = currIdx == this.someobslist.Count - 1 ? this.someobslist[0] : this.someobslist[currIdx + 1];
});
Thats it. In case you need a RelayCommand, i can hand you mine. Of course replace my Varaibles with yours.
This Solution circles now through the TabItems
EDIT
Here is a plain scrollcycler without navigating to the TabItem, based on this <--- IMPORTANT
Add to your ScrollViewer a Loaded-Event in XAML
Here the code:
private int _scollMoverIdx = 0;
private TabControl _container;
private void ScrollViewer_OnLoaded(object sender, RoutedEventArgs e) {
this._container = (sender as ScrollViewer).TemplatedParent as TabControl;
}
public ICommand MoveLeftCommand => new RelayCommand(x => {
if (this._scollMoverIdx == 0) {
this._scollMoverIdx = this.someobslist.Count - 1;
this._container.ScrollToCenterOfView(this.someobslist[_scollMoverIdx]);
} else {
_scollMoverIdx--;
this._container.ScrollToCenterOfView(this.someobslist[_scollMoverIdx]);
}
});
public ICommand MoveRightCommand => new RelayCommand(x => {
if (this._scollMoverIdx == this.someobslist.Count - 1) {
this._scollMoverIdx = 0;
this._container.ScrollToCenterOfView(this.someobslist[_scollMoverIdx]);
} else {
_scollMoverIdx++;
this._container.ScrollToCenterOfView(this.someobslist[_scollMoverIdx]);
}
});
Its not really pretty, but i wanted to keep it simple. The linked Extension method is greate for reusability (Credits to Ray Burns). If you want this to be MVVM-conform, i suggest making a CustomControl, since scrolling from ViewModel is breaking the pattern.
Cheers

check PasswordBox Value WPF

I have a password box, but i also have a textblock as hint text within the control template. I'd like this to be removed when the password box has a value. I have tried this below but it doesn't work, how can I do this?
Simplified XAML :
<PasswordBox Height="20" Name="pwdBox" PasswordChanged="pwdBox_PasswordChanged" Style="{DynamicResource PasswordBoxStyle1}"/>
<Style x:Key="PasswordBoxStyle1" TargetType="{x:Type PasswordBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type PasswordBox}">
<Border x:Name="Border" .. >
<StackPanel ..>
<TextBlock x:Name="LabelTextBlock" ...
Text="Password Label" />
<Grid>
<ScrollViewer x:Name="PART_ContentHost"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"/>
<TextBlock x:Name="HintTextBlock"
Focusable="False"
IsHitTestVisible="False"
Opacity="0"
Text="Enter Your Password" />
</Grid>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Code Behind :
private void pwdBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (pwdBox.SecurePassword.Length == 0)
{
HintTextBlock.IsVisible = true;
}
else
{
HintTextBlock.IsVisible = false;
}
}
It says that the name 'HintTextBlock does not exist in the current context'
Since, the text box HintTextBlock is part of Template of PassworkBox so it can not accessed directly as it is not part of direct control of window. Use the FindName to find the control in template of passwordbox.
TextBlock hintTextBlock = pwdBox.Template.FindName("HintTextBlock", pwdBox) as TextBlock;
if (pwdBox.SecurePassword.Length == 0)
{
hintTextBlock.Visiblility = Visiblitity.Visible;
}
else
{
hintTextBlock.Visiblility = Visiblility.Collapsed;
}

Get TreeViewItem's parent in HierarchicalDataTemplate in WPF

I am merging two examples found on the internet. One about stretched selection styles and one about multi-selection in a treeview.
I have everything working, except for the indentations of the treeview. I could give all my code, but that wouldn't solve it.
My problem lies in the following method:
public static class TreeViewItemExtensions
{
public static int GetDepth(this TreeViewItem item)
{
FrameworkElement elem = item;
while (elem.Parent != null)
{
var tvi = elem.Parent as TreeViewItem;
if (tvi != null)
return tvi.GetDepth() + 1;
elem = elem.Parent as FrameworkElement;
}
return 0;
}
}
This method tries to retrieve the depth of a treeviewItem in the tree. The problem is: elem.Parent is always null. Which results in depths of 0.
I think this is happening, because I am using an HierarchicalDataTemplate. A part of my xaml looks like this.
<TreeView Name="folderTree"
ItemsSource="{Binding Folders}"
SelectedItemChanged="folderTree_SelectedItemChanged"
HorizontalContentAlignment="Stretch">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Folders}"
DataType="{x:Type Model:IFolder}">
<StackPanel Orientation="Horizontal">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}"
Value="True">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<Image Source="{Binding Converter={StaticResource iconConverter}}" Height="{Binding ElementName=theFile,Path=ActualHeight}"/>
<TextBlock Text="{Binding FileName}" Name="theFile"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
The XAML for my style of the treeview looks like this:
<Style x:Key="{x:Type TreeViewItem}" TargetType="{x:Type TreeViewItem}">
<!-- leaving some stuff out here -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<ControlTemplate.Resources>
<local:LeftMarginMultiplierConverter Length="19" x:Key="lengthConverter" />
</ControlTemplate.Resources>
<StackPanel>
<!-- The upper part of the TreeViewItem -->
<Border Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<!-- The margin is what we try to measure, how can we get the parents from the templatedParents? -->
<Grid Margin="{Binding Converter={StaticResource lengthConverter},
RelativeSource={RelativeSource TemplatedParent},
Path=.}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="19" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ToggleButton x:Name="Expander"
Style="{StaticResource ExpandCollapseToggleStyle}"
IsChecked="{Binding Path=IsExpanded,
RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press"/>
<ContentPresenter x:Name="PART_Header"
Grid.Column="1"
ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Grid>
</Border>
<!-- the children of the TreeViewItem -->
<ItemsPresenter x:Name="ItemsHost" />
</StackPanel>
<!-- leaving some stuff out here with triggers -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How can I make the HierarchicalDataTemplate fill the Parent property?
I'd scan the visual tree instead.
Here is a simple (even not-so-elegant) solution:
public static class TreeViewItemExtensions
{
public static int GetDepth(this TreeViewItem item)
{
DependencyObject target = item;
var depth = 0;
while (target != null)
{
if (target is TreeView)
return depth;
if (target is TreeViewItem)
depth++;
target = VisualTreeHelper.GetParent(target);
}
return 0;
}
}
Cheers.

Categories

Resources