Problem
I have a Listbox control and when a user clicks a button they are able to add items to the control.
The issue I am having is that the Listbox control itself is not refreshing and displaying the new values that the user has added. I have debugged the code and the datasource is being updated with the new values.
Anyone have any ideas?
Code
The C#:
ObservableCollection<ITimeLineDataItem> listboxData = new ObservableCollection<ITimeLineDataItem>();
public ObservableCollection<ITimeLineDataItem> ListBoxData
{
get
{
return listboxData;
}
}
public Live()
{
InitializeComponent();
this.DataContext = this;
}
public void RefreshListbox()
{
ListSrc.ItemsSource = null;
//THE CODE GOES HERE WHERE I UPDATE THE DATASOURCE.
ListSrc.ItemsSource = ListBoxData;
}
XAML:
<Border BorderBrush="#d6786a" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderThickness="2" Grid.Column="15" Grid.Row="5" Grid.ColumnSpan="3">
<ListBox x:Name="ListSrc" Background="#ececec" ItemsSource="{Binding Path=ListBoxData}" dd:DragDrop.IsDragSource="True" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" BorderBrush="Transparent" BorderThickness="0">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="10" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" Margin="15"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.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" />
</ListBox.Resources>
</ListBox>
</Border>
You don't need to refresh. If the new item is added correctly to the source it should be visible on the list. However, can you update your post with the button click event code?
Related
Good evening guys,
I'd really like to have a custom button with text and vector icon.. I searched for something similar but no luck..so I tried by myself to make a custom control but I am not able to make it works: no errors or warnings found but the icon doesn't appear at all.
Here below my code:
Custom control CS:
public class ThButton : Button
{
static ThButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ThButton), new FrameworkPropertyMetadata(typeof(ThButton)));
}
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(Path), typeof(ThButton), new UIPropertyMetadata(null));
public Path Icon
{
get { return (Path)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty ThLabelProperty =
DependencyProperty.Register("ThLabel", typeof(string), typeof(ThButton), new UIPropertyMetadata(null));
public String ThLabel
{
get { return (String)GetValue(ThLabelProperty); }
set { SetValue(ThLabelProperty, value); }
}
}
generic.xaml (triggers etc. removed since not useful for this):
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControlTest">
<Path x:Key="BoatIcon" Fill="Black" Data="M6,6H18V9.96L12,8L6,9.96M3.94,19H4C5.6,19 7,18.12 8,17C9,18.12 10.4,19 12,19C13.6,19 15,18.12 16,17C17,18.12 18.4,19 20,19H20.05L21.95,12.31C22.03,12.06 22,11.78 21.89,11.54C21.76,11.3 21.55,11.12 21.29,11.04L20,10.62V6C20,4.89 19.1,4 18,4H15V1H9V4H6A2,2 0 0,0 4,6V10.62L2.71,11.04C2.45,11.12 2.24,11.3 2.11,11.54C2,11.78 1.97,12.06 2.05,12.31M20,21C18.61,21 17.22,20.53 16,19.67C13.56,21.38 10.44,21.38 8,19.67C6.78,20.53 5.39,21 4,21H2V23H4C5.37,23 6.74,22.65 8,22C10.5,23.3 13.5,23.3 16,22C17.26,22.65 18.62,23 20,23H22V21H20Z" />
<Color x:Key="BackgroundColor1" A="255" R="0" G="133" B="209"/>
<Color x:Key="BackgroundColor2" A="255" R="0" G="61" B="94"/>
<Color x:Key="MouseOverBackgroundColor1" A="255" R="0" G="156" B="231"/>
<Color x:Key="MouseOverBackgroundColor2" A="255" R="0" G="90" B="155"/>
<Color x:Key="MousePressedBackgroundColor1" A="255" R="0" G="98" B="195"/>
<Color x:Key="MousePressedBackgroundColor2" A="255" R="0" G="36" B="72"/>
<Color x:Key="IsNotEnabledBackgroundColor1" A="255" R="233" G="233" B="233"/>
<Color x:Key="IsNotEnabledBackgroundColor2" A="255" R="240" G="240" B="240"/>
<SolidColorBrush x:Key="ThBorderBrush" Color="#ECECEC"></SolidColorBrush>
<Style TargetType="{x:Type local:ThButton}">
<Setter Property="BorderBrush" Value="{StaticResource ThBorderBrush}"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ThButton}">
<Border x:Name="t"
Margin="{TemplateBinding Margin}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="6">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop x:Name="BackgroundGradientStop1" Offset="0" Color="{StaticResource BackgroundColor1}"/>
<GradientStop x:Name="BackgroundGradientStop2" Offset="1" Color="{StaticResource BackgroundColor2}"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<Rectangle Width="20" Height="20" Fill="black" Margin="0,0,0,5">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{TemplateBinding Icon}"/>
</Rectangle.OpacityMask>
</Rectangle>
<Label Content="{TemplateBinding ThLabel}"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And finally mainWindow.xaml:
<local:ThButton Width="100" Icon="{StaticResource BoatIcon}" ThLabel="Test"/>
if I put the "{StaticResource BoatIcon}" in place of "{TemplateBinding Icon}" in Visual (generic.xaml) the icon appears so I suppose the problem is all about how I tried to use the DependencyProperty.
This can be done using a custom UserControl quite easily.
First, add your image to your project resources, and make 'Build Type = Resource' in the properties. Do this by selecting the newly added image and right clicking, then setting the above property.
Next, create a UserControl. Here's my XAML
<UserControl x:Class="ListViewDragAndDrop.UCPictureButton"
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"
xmlns:local="clr-namespace:ListViewDragAndDrop"
mc:Ignorable="d"
d:DesignHeight="32" d:DesignWidth="128">
<Grid>
<Button Click="Button_Click">
<StackPanel Orientation="Horizontal">
<Image Source="/Resources/solution.png"
Margin="4, 4, 8, 4"/>
<TextBlock Text="Button Text"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
</Button>
</Grid>
</UserControl>
Make sure the 'Source' of the image is correct. What's shown above is where it's in my project which is the default.
Then the UserControl code behind:
public partial class UCPictureButton : UserControl
{
public event RoutedEventHandler RoutedButtonClick;
public UCPictureButton()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
RoutedButtonClick?.Invoke(this, e);
}
}
In the button click event, we invoke the RoutedEvent we declared there.
Now on your Main window or wherever you want to use the button:
<local:UCPictureButton Grid.Column="2" Width="120" Height="32">
<i:Interaction.Triggers>
<i:EventTrigger EventName="RoutedButtonClick">
<i:InvokeCommandAction Command="{Binding CmdButtonClick}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</local:UCPictureButton>
The i namespace is the interactivity namespace:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Now all you have to do is in your ViewModel simply hook up a method to the above declared CmdButtonClick command.
I'm using the MVVM Light toolkit and it looks like this:
public RelayCommand CmdButtonClick { get; private set; }
public MainViewModel(IDataService dataService)
{
CmdButtonClick = new RelayCommand(ButtonClick);
}
private void ButtonClick()
{
// Button action
}
Result:
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.
I have a GanttControl with a TaskItemTemplate containing a Grid and a Rectangle which is responsible for the appearence of the tasks. The Rectangle has the properties Fill and Stroke. These properties are being set from StaticResources where the color of the tasks are defined. I try to bind the LinearGradientBrush to the property Color of my model.
There is my Xaml code:
<LinearGradientBrush x:Key="ParentBarFill" StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="Black" Offset="0" />
<GradientStop Color="White" Offset="0.1" />
<GradientStop Color="Gray" Offset="0.2" />
<GradientStop Color="Black" Offset="0.6" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
** />
<SolidColorBrush x:Key="TaskItemBarStroke" Color="{Binding Color}"/> **<!--There is the Problem too-->**
<!-- Task look and feel styles -->
<!--Transparent-->
<Style TargetType="Thumb" x:Name="TransparentThumb" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Grid>
<Border CornerRadius="2" Background="Transparent" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<flexyGantt:FlexyGantt x:Name="fxgantt" Grid.Row="1" Grid.Column="0" ItemTemplate="{StaticResource TreeTemplate}"
TaskListBinding="{Binding EngineersInterval}" TaskStartTimeBinding="{Binding StartInteval, Mode=TwoWay}"
TaskEndTimeBinding="{Binding FinishInterval, Mode=TwoWay}" ParentTaskStartTimeBinding="{Binding OverallStartTime}"
ParentTaskEndTimeBinding="{Binding OverallEndTime}"
TreeHeaderContent="Teams" CustomSourceListViewTemplate="{StaticResource flexyGanttTableTemplate}"
OverlappedTasksRenderingOptimization="ShrinkHeight" RowHeight="25" TaskTimeChanged="Fxgantt_OnTaskTimeChanged"
>
<flexyGantt:FlexyGantt.TaskItemTemplate>
<DataTemplate>
<Grid ToolTipService.ToolTip="{Binding ToolTipText}">
<Rectangle x:Name="taskBar" HorizontalAlignment="Stretch"
Fill="{StaticResource TaskItemBarFill}" Stroke="{StaticResource TaskItemBarStroke}"
StrokeThickness="1" RadiusX="4" RadiusY="4"/>
<!--Include a thumb with name "dragThumb" to enable drag-moving the task functionality.
ZIndex=2 ensures this is drawn above the Rectangle-->
<Thumb x:Name="dragThumb" Canvas.ZIndex="2" Style="{StaticResource TransparentThumb}" />
<!--Include a thumb with name "resizeThumb" to enable resizing the task functionality
ZIndex=3 ensures this is drawn above the dragThumb-->
<Thumb x:Name="resizeThumb" Canvas.ZIndex="4" HorizontalAlignment="Right" Cursor="SizeWE"
Style="{StaticResource TransparentThumb}" Width="3" />
<!--Include a thumb with name "resizeStartThumb" to enable resizing to the left (changing starttime) functionality
ZIndex=3 ensures this is drawn above the dragThumb-->
<Thumb x:Name="resizeStartThumb" Canvas.ZIndex="3" HorizontalAlignment="Left" Cursor="SizeWE"
Style="{StaticResource TransparentThumb}" Width="3" Height="14"/>
</Grid>
</DataTemplate>
</flexyGantt:FlexyGantt.TaskItemTemplate>
</flexyGantt:FlexyGantt>
How can I bind this? Also me Model :
public class GanttIntervalModel : INotifyPropertyChanged
{
public Color Color
{
get { return _color; }
set
{
if (Equals(value, _color)) return;
_color = value;
OnPropertyChanged(nameof(Color));
}
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I have created slightly customized vertical scrollbar for my DataGrid. In it I have added an ItemsControl to hold positions of the selected items. Here is a mockup so far with hard-coded markers.
Below is my customized vertical scrollbar template where the ItemsControl is placed with hard-coded marker values.
<ControlTemplate x:Key="VertScrollBar" TargetType="{x:Type ScrollBar}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition MaxHeight="18" />
<RowDefinition Height="0.00001*" />
<RowDefinition MaxHeight="18" />
</Grid.RowDefinitions>
<Border Grid.RowSpan="3" CornerRadius="2" Background="#F0F0F0" />
<RepeatButton Grid.Row="0" Style="{StaticResource ScrollBarLineButton}" Height="18" Command="ScrollBar.LineUpCommand" Content="M 0 4 L 8 4 L 4 0 Z" />
<Track x:Name="PART_Track" Grid.Row="1" IsDirectionReversed="true">
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollBarPageButton}" Command="ScrollBar.PageUpCommand" />
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource ScrollBarThumb}" Margin="1,0,1,0">
<Thumb.BorderBrush>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="{DynamicResource BorderLightColor}" Offset="0.0" />
<GradientStop Color="{DynamicResource BorderDarkColor}" Offset="1.0" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Thumb.BorderBrush>
<Thumb.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="{DynamicResource ControlLightColor}" Offset="0.0" />
<GradientStop Color="{DynamicResource ControlMediumColor}" Offset="1.0" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Thumb.Background>
</Thumb>
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollBarPageButton}" Command="ScrollBar.PageDownCommand" />
</Track.IncreaseRepeatButton>
</Track>
<!-- BEGIN -->
<ItemsControl Grid.Column="0" VerticalAlignment="Stretch" Name="ItemsSelected">
<sys:Double>30</sys:Double>
<sys:Double>70</sys:Double>
<sys:Double>120</sys:Double>
<sys:Double>170</sys:Double>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Fill="SlateGray" Width="18" Height="4"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Top" Value="{Binding}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<!-- END -->
<RepeatButton Grid.Row="3" Style="{StaticResource ScrollBarLineButton}" Height="18" Command="ScrollBar.LineDownCommand" Content="M 0 0 L 4 4 L 8 0 Z" />
</Grid>
</ControlTemplate>
What I am trying to do next is create an AttachedProperty to hold marker positions and bind it back to the ItemsControl.
What I don't really understand is:
- What should this attached property Type be, an ObservableCollection of int's?
- As this is a guide to the total selected items in the DataGrid, do the positions of the markers need to be scaled somehow?
- I have an attached behavior that captures DataGrid.SelectionChanged, but what about if the main collection changes there doesn't seem to be an event for this?
[EDIT]
To bind directly to the DataGrids SelectedItems. (However there is a flicker in the top of the ItemsControl when something is selected)
- Remove or comment out the SelectionChanged behavior.
- Change the ItemSource to:
ItemsSource="{Binding ElementName=GenericDataGrid, Path=SelectedItems}"
- Change Multibinding to:
<MultiBinding Converter="{StaticResource MarkerPositionConverter}">
<Binding/>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}" />
<Binding Path="ActualHeight" ElementName="ItemsSelected"/>
<Binding Path="Items.Count" ElementName="GenericDataGrid"/>
</MultiBinding>
- And lastly converter to:
public class MarkerPositionConverter: IMultiValueConverter
{
//Performs the index to translate conversion
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//calculated the transform values based on the following
object o = (object)values[0];
DataGrid dg = (DataGrid)values[1];
double itemIndex = dg.Items.IndexOf(o);
double trackHeight = (double)values[2];
int itemCount = (int)values[3];
double translateDelta = trackHeight / itemCount;
return itemIndex * translateDelta;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I attempted to achieve your desired result
so for that I have made some changes, I've commented where I have made changes
add this converter reference to the resources
<helpers:MarkerPositionConverter x:Key="MarkerPositionConverter"/>
Items control xaml which is showing the markers
<!-- added Grid.Row="1", removed other attributes, removed the ItemsControlBeahviors, not much needed-->
<ItemsControl Grid.Row="1" Name="ItemsSelected"
ItemsSource="{Binding Source={x:Static helpers:MyClass.Instance}, Path=SelectedMarkers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--you can optionally bind height to scale accordingly if needed-->
<Rectangle Fill="#99708090" Width="18" Height="4">
<Rectangle.RenderTransform>
<!--added a translate transform-->
<TranslateTransform>
<TranslateTransform.Y>
<!--multi binded Y to the item and the actual height of MarkerItems control using the new MarkerPositionConverter-->
<MultiBinding Converter="{StaticResource MarkerPositionConverter}">
<Binding/>
<Binding Path="ActualHeight" ElementName="ItemsSelected"/>
</MultiBinding>
</TranslateTransform.Y>
</TranslateTransform>
</Rectangle.RenderTransform>
</Rectangle>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
behavior.cs
public class DataGridBehaviors : Behavior<DataGrid>
{
...
void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
MyClass.Instance.SelectedMarkers.Clear();
//updated item count
MyClass.Instance.ItemCount = this.AssociatedObject.Items.Count;
foreach (object o in this.AssociatedObject.SelectedItems)
MyClass.Instance.SelectedMarkers.Add(this.AssociatedObject.Items.IndexOf(o));
}
}
//removed ItemsControlBeahviors
public class MyClass : INotifyPropertyChanged
{
...
//added item count property
public int ItemCount { get; set; }
...
}
//added class to perform the index to translate conversion
public class MarkerPositionConverter: IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//calculated the transform values based on the following
double itemIndex = (double)values[0];
double trackHeight = (double)values[1];
double translateDelta = trackHeight / MyClass.Instance.ItemCount;
return itemIndex * translateDelta;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
now you may customize it as per your needs
Remove flicker
the flicker is due to the initial placement of the rectangle and before the binding gets all of its values so to avoid this initial intermittent flicker use this
<!--added fallback value to avoid intermittent value-->
<MultiBinding Converter="{StaticResource MarkerPositionConverter}" FallbackValue="-1000">
<Binding/>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}" />
<Binding Path="ActualHeight" ElementName="ItemsSelected"/>
<Binding Path="Items.Count" ElementName="GenericDataGrid"/>
</MultiBinding>
so I placed the rectangle out of the view by pushing it back 1000 px when any of the binded property is busy in resolving the value or does not have any value.
and in items panel template (optional)
<ItemsPanelTemplate>
<!--added ClipToBounds to be extra safe-->
<Canvas ClipToBounds="True"/>
</ItemsPanelTemplate>
since the canvas by default does not clip its children, set ClipToBounds to true to be safe. this is necessary when the flicker is still visible somewhere in the UI even after using a huge fallback value.
I want to change the background color of ListBoxItem
After search I decide to use this
<ListBox>
<ListBox.Resources>
<!-- Background of selected item when focussed -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Blue" />
<!-- Background of selected item when not focussed -->
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
Color="Blue" />
</ListBox.Resources>
<TextBlock>fdfsdf1</TextBlock>
<TextBlock>fdfsdf3</TextBlock>
<TextBlock>fdfsdf5</TextBlock>
<TextBlock>fdfsdf3</TextBlock>
<TextBlock>fdfsdf4</TextBlock>
</ListBox>
When a listboxitem is focused, the background is blue as expected, but when the selected listboxitem loses focus, the background turns gray. How can I make the background remain blue when it loses focus?
if you mean just when its selected but inactive try InactiveSelectionHighlightBrushKey
<ListBox.Resources>
<!-- Background of selected item when focussed -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Blue" />
<!-- Background of selected item when not focussed -->
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
Color="Blue" />
</ListBox.Resources>
Try this
<ListBox>
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="Blue" />
</Style>
</ListBox.Resources>
<TextBlock>fdfsdf1</TextBlock>
<TextBlock>fdfsdf3</TextBlock>
<TextBlock>fdfsdf5</TextBlock>
<TextBlock>fdfsdf3</TextBlock>
<TextBlock>fdfsdf4</TextBlock>
</ListBox>
if you think the system color keys are not working for you then you can force it by creating new style for ListboxItems as like below.
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Silver"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
This is what I used to select the color for the active/inactive items of a ListBox:
<ListBox Name="lbExample" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<...>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Resources>
<!-- Background of selected item when not focussed -->
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="AntiqueWhite" />
</Style>
<!-- Background of selected item when focussed -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightGreen" />
</ListBox.Resources>
</ListBox>
I'm using MaterialDesignThemes and Caliburn Micro to make a ListBox that can have multiple selections. None of these other answers worked. What did work for me was in the ViewModel.xaml:
<ListBox Padding="2" Margin="5" Grid.Column="1" Grid.Row="4" Name="Field1Items" SelectionMode="Multiple" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="Background" Value="{Binding ListBoxItemBackground}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Then having this class to encapsulate all my items:
public class MultiSelectItem : PropertyChangedBase
{
public MultiSelectItem (string name)
{
this.Name = name;
_isSelected = false;
}
public string Name { get; set; }
bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
NotifyOfPropertyChange(() => IsSelected);
NotifyOfPropertyChange(() => ListBoxItemBackground);
}
}
public string ListBoxItemBackground
{
get
{
if (IsSelected)
return "#e0e0e0";
return "Transparent";
}
}
public override string ToString()
{
return Name;
}
}
and in the ViewModelClass:
public BindableCollection<MultiSelectItem> Field1Items
{
get
{
return _field1Items;
}
}