WPF GroupStyle only for Groups with more than 1 item - c#

I am trying to show different Groups in a Listview which contain an expander and a header. However I don't want my SecondLevel Group to show a header if the Group only contains 1 item.
Since this would be quite inconvenient.
My Code:
<Window x:Class="ListViewGrouping.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:listViewGrouping="clr-namespace:ListViewGrouping"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<listViewGrouping:GroupItemStyleSelector x:Key="groupItemStyleSelector"/>
<!-- Style for the first level GroupItem -->
<Style x:Key="FirstLevel" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="3.5,0" Text="{Binding Name}" TextBlock.FontWeight="Bold"/>
<TextBlock Grid.Column="1" Margin="3.5,0" Text="Elements:"/>
<TextBlock Grid.Column="2" Margin="3.5,0" Text="{Binding ItemCount}"/>
</Grid>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Style for the second level GroupItem -->
<Style x:Key="SecondLevel" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" Margin="15,0,0,0">
<Expander.Header>
<TextBlock Text="{Binding Name}" TextBlock.FontWeight="Bold"/>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ListView Name="mailView" ItemsSource="{Binding}">
<ListView.GroupStyle>
<GroupStyle ContainerStyleSelector="{StaticResource groupItemStyleSelector}" />
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Header="Subject" DisplayMemberBinding="{Binding Subject}"/>
<GridViewColumn Header="Sender" DisplayMemberBinding="{Binding Sender}"/>
<GridViewColumn Header="Support-ID" DisplayMemberBinding="{Binding Support_ID}"/>
<GridViewColumn Header="Supporter" DisplayMemberBinding="{Binding Supporter}"/>
<GridViewColumn Header="Received" DisplayMemberBinding="{Binding ReceivedDate}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
Code behind:
private void createMailList()
{
_mails.Add(new Mail("LIC", "Lizenz geht nicht", "Xeun", "LIC.2013.01.10.002", "Xeun", "25.09.2013"));
_mails.Add(new Mail("CD", "Alles doof", "Xeun", "CD.2013.01.10.002", "Xeun", "25.09.2013"));
_mails.Add(new Mail("CD", "Re:Alles doof", "Xeun", "CD.2013.01.10.002", "Xeun", "25.09.2013"));
_mails.Add(new Mail("CD", "CD kaputt", "Xeun", "CD.2013.01.10.003", "Xeun", "25.09.2013"));
_mails.Add(new Mail("CD", "Geht nicht", "Xeun", "CD.2013.01.10.001", "Xeun", "25.09.2013"));
_mails.Add(new Mail("LIC", "Kaputt", "Xeun", "LIC.2013.01.10.001", "Xeun", "25.09.2013"));
}
public MainWindow()
{
InitializeComponent();
createMailList();
DataContext = _mails;
ICollectionView view = CollectionViewSource.GetDefaultView(_mails);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("ID");
view.GroupDescriptions.Add(groupDescription);
view.GroupDescriptions.Add(new PropertyGroupDescription("Support_ID"));
}
}
public class GroupItemStyleSelector : StyleSelector
{
public override Style SelectStyle(object item, DependencyObject container)
{
Style s;
CollectionViewGroup group = item as CollectionViewGroup;
Window window = Application.Current.MainWindow;
if (!group.IsBottomLevel)
{
s = window.FindResource("FirstLevel") as Style;
}
else
{
s = window.FindResource("SecondLevel") as Style;
}
return s;
}
}
I hope I explained my problem well enough - I have attached a screenshot of the small app - the Groups marked as red only contain one item and should not be shown as group.

For both styles split the ControlTemplate in 2, one with an expander and one with out.
Create a converter which checks the if the group size (your group is of type CollectionViewGroup)
return yourGroup.Items.Count > 1
Place a DataTrigger as seen below in each style which checks the groups size via the converter
(your DataContext is your group so the binding is Binding="{Binding}"
xaml :
<ControlTemplate TargetType="{x:Type GroupItem}" x:Key="withExpander">
<Expander IsExpanded="True">
<Expander.Header>
.....
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
<ControlTemplate TargetType="{x:Type GroupItem}" x:Key="withOutExpander">
<ItemsPresenter />
</ControlTemplate>
<Style x:Key="FirstLevel" TargetType="{x:Type GroupItem}">
<Setter Property="Template" Value="{StaticResource withExpander}" />
<Style.Triggers>
<DataTrigger Binding="{Binding , Converter={StaticResource GroupSizeToExpanderConverter}" Value="False">
<Setter Property="Template" Value="{StaticResource withOutExpander}"/>
</DataTrigger>
</Style.Triggers>
</Style>
Edit :
*the converter value will be the Group itself (of type CollectionViewGroup)
The Converter :
public class GroupSizeToExpanderConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
CollectionViewGroup grp = (CollectionViewGroup)value;
return grp.Items.Count() > 1; // ALTERNATIVLY grp.ItemCount;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

here is my solution
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Expander IsExpanded="True">
<Expander.Style>
<Style TargetType="Expander">
<Setter Property="Visibility" Value="Visible"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ItemCount}" Value="1">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" FontWeight="Bold" Foreground="Gray" FontSize="22" VerticalAlignment="Bottom" />
<TextBlock Text="{Binding ItemCount}" FontSize="22" Foreground="Green" FontWeight="Bold" FontStyle="Italic" Margin="10,0,0,0" VerticalAlignment="Bottom" />
<TextBlock Text=" item(s)" FontSize="22" Foreground="Silver" FontStyle="Italic" VerticalAlignment="Bottom" />
</StackPanel>
</Expander.Header>
<Border BorderBrush="LightBlue" BorderThickness="2" Margin="0 2">
<ItemsPresenter />
</Border>
</Expander>
<ItemsPresenter>
<ItemsPresenter.Style>
<Style TargetType="ItemsPresenter">
<Setter Property="Visibility" Value="Collapsed"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ItemCount}" Value="1">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsPresenter.Style>
</ItemsPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>

Related

Horizontal aligment WPF expander header

I want to show my GroupName on left and button "ShowOnly" on the right of header row.
I tried with this code but doesn't works.
Could anyone help me?
Thx
My code :
<Expander IsExpanded="True" >
<Expander.Header>
<DockPanel HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Path=Name}" FontSize="18"></TextBlock>
<Button Style="{StaticResource ButtonStyle}" Content="Show Only" HorizontalAlignment="Right" Padding="15,0,15,0" Click="Button_Click"></Button>
</DockPanel>
</Expander.Header>
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Setter Property="Background" Value="#f0f0f5"></Setter>
<Setter Property="TextElement.FontFamily" Value="Arial Nova"/>
</Style>
</Expander.Style>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
My ButtonStyle :
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#66e0ff" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="15" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="4" Background="{TemplateBinding Background}">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="White" />
<Setter Property="Foreground" Value="#66e0ff" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I tried also with an DockPanel, but same result.
You need to set the HorizontalAlignment property of the ContentPresenter that is defined in the Expander's default control template to Stretch.
The easiest way to do this is probably to handle the Loaded event of the Expander and use a helper method that finds the ContentPresenter in the visual tree:
private void Expander_Loaded(object sender, RoutedEventArgs e)
{
Expander expander = sender as Expander;
System.Windows.Controls.Primitives.ToggleButton HeaderSite = GetChildOfType<System.Windows.Controls.Primitives.ToggleButton>(expander);
if (HeaderSite != null)
{
ContentPresenter cp = GetChildOfType<ContentPresenter>(HeaderSite);
if (cp != null)
cp.HorizontalAlignment = HorizontalAlignment.Stretch;
}
}
private static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
<Expander IsExpanded="True" Loaded="Expander_Loaded">
<Expander.Header>
<DockPanel HorizontalAlignment="Stretch">
<Button Style="{StaticResource ButtonStyle}" Content="Show Only" DockPanel.Dock="Right" Padding="15,0,15,0" Click="Button_Click"></Button>
<TextBlock Text="{Binding Path=Name}" FontSize="18"></TextBlock>
</DockPanel>
</Expander.Header>
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Setter Property="Background" Value="#f0f0f5"></Setter>
<Setter Property="TextElement.FontFamily" Value="Arial Nova"/>
</Style>
</Expander.Style>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
Set width of DockPanel to width of expander so that it will stretch properly.
<DockPanel HorizontalAlignment="Stretch" Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Expander}}, Path=ActualWidth}">
You can refer to these solutions:
https://joshsmithonwpf.wordpress.com/2007/02/24/stretching-content-in-an-expander-header/

How To Style Modern UI RadialGaugeChart

I'm using Modern UI Charts in my project (Modern UI Charts), and I'm trying to change the chart foreground and palette based on ValueMember.
I have a converter:
public class MetricsColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//Dim num As Integer
string color = null;
decimal intValue = default(decimal);
if (decimal.TryParse(value.ToString(), intValue)) {
if (intValue <= 60.0) {
return "Red";
} else if (intValue >= 60.01 && intValue < 80.0) {
return "Yellow";
} else if (intValue >= 80.01) {
return "Green";
}
}
return color;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And my xaml with a chart:
<chart:RadialGaugeChart
ChartTitleVisibility="Collapsed"
ChartLegendVisibility="Collapsed"
ToolTipFormat="{}Caption: {0}, Value: '{1}', Series: '{2}', Percentage: {3:P2}"
HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5,5,5,5" Height="170" >
<chart:RadialGaugeChart.Style>
<Style TargetType="{x:Type chart:RadialGaugeChart}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ProductivitySeries, Path=ValueMember, Converter={StaticResource MetricsConverter}}" Value="Green">
<Setter Property="Foreground" Value="{StaticResource Flat_GreenAccentBrush}"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=ProductivitySeries, Path=ValueMember, Converter={StaticResource MetricsConverter}} "Value="Yellow">
<Setter Property="Foreground" Value="{StaticResource Flat_MetricYellowBrush}"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=ProductivitySeries, Path=ValueMember, Converter={StaticResource MetricsConverter}}" Value="Red">
<Setter Property="Foreground" Value="{StaticResource Flat_MetricRedBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</chart:RadialGaugeChart.Style>
<chart:RadialGaugeChart.Series>
<chart:ChartSeries
Name="ProductivitySeries"
SeriesTitle="Productivity"
ItemsSource="{Binding TeamLeaderViewM.TeamLeaderMetrics}"
DisplayMember="TeamLeader"
ValueMember="Productivity"/>
</chart:RadialGaugeChart.Series>
</chart:RadialGaugeChart>
Unfortunately, nothing is changing here. Color is the same, all the time.
How can I implement this to my charts?
Thank you for suuggestions
You have to modify the default PlotterArea style as shown below:
<Window
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:local="clr-namespace:WpfApplication1"
xmlns:MetroChart="clr-namespace:De.TorstenMandelkow.MetroChart;assembly=De.TorstenMandelkow.MetroChart"
x:Class="WpfApplication1.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/De.TorstenMandelkow.MetroChart;component/Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
<local:MetricsColorConverter x:Key="Converter1"></local:MetricsColorConverter>
<x:Array x:Key="SampleData1" Type="{x:Type local:MyData}">
<local:MyData TeamLeader="Team A" Productivity="50"></local:MyData>
<local:MyData TeamLeader="Team B" Productivity="75"></local:MyData>
<local:MyData TeamLeader="Team C" Productivity="90"></local:MyData>
</x:Array>
<Style x:Key="RadialGaugeChartPlotterAreaStyle1" TargetType="MetroChart:PlotterArea">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MetroChart:PlotterArea">
<MetroChart:FadingListView Style="{StaticResource FadingListViewStyle}" ItemsSource="{Binding Path=ParentChart.DataPointGroups, RelativeSource={RelativeSource Mode=TemplatedParent}}">
<MetroChart:FadingListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</MetroChart:FadingListView.ItemsPanel>
<MetroChart:FadingListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="0" Visibility="{Binding Path=ShowCaption, Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock Text="{Binding Path=Caption}" Style="{StaticResource SeriesTitleStyle}" />
</Border>
<MetroChart:FadingListView Style="{StaticResource FadingListViewStyle}"
x:Name="itemsControl"
ItemsSource="{Binding Path=DataPoints}"
Margin="5"
Grid.Row="1">
<MetroChart:FadingListView.ItemsPanel>
<ItemsPanelTemplate>
<!--<StackPanel Orientation="Horizontal" />-->
<MetroChart:UniformGridPanel Orientation="Horizontal" MinimalGridWidth="150.0" />
</ItemsPanelTemplate>
</MetroChart:FadingListView.ItemsPanel>
<MetroChart:FadingListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<MetroChart:RadialGaugePiece
Grid.Row="0"
Margin="5"
Background="{Binding Path=Value, Converter={StaticResource Converter1}}"
SelectedBrush="{Binding Path=SelectedBrush}"
Value="{Binding Path=Value}"
IsClickedByUser="{Binding Path=IsClickedByUser, Mode=TwoWay}"
IsSelected="{Binding Path=IsSelected}"
ClientWidth="180"
ClientHeight="180"
x:Name="radial">
</MetroChart:RadialGaugePiece>
<Border Grid.Row="1" HorizontalAlignment="Center" Margin="0 0 0 10">
<TextBlock Text="{Binding Path=SeriesCaption}" />
</Border>
</Grid>
</DataTemplate>
</MetroChart:FadingListView.ItemTemplate>
</MetroChart:FadingListView>
</Grid>
</DataTemplate>
</MetroChart:FadingListView.ItemTemplate>
</MetroChart:FadingListView>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid>
<MetroChart:RadialGaugeChart ChartTitle="My Sample"
ChartSubTitle="Productivity"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
PlotterAreaStyle="{StaticResource RadialGaugeChartPlotterAreaStyle1}">
<MetroChart:RadialGaugeChart.Series>
<MetroChart:ChartSeries Name="ProductivitySeries"
SeriesTitle="My Series"
DisplayMember="TeamLeader"
ValueMember="Productivity"
ItemsSource="{StaticResource SampleData1}" />
</MetroChart:RadialGaugeChart.Series>
</MetroChart:RadialGaugeChart>
</Grid>

How to bind List of Objects to a ListBox

I have tried to bind a List of objects to a ListBox, but when run it has no items in the ListBox, the List itself does have items.
List<Module> _modules
public class Module
{
public Module(string ModuleName, string ModuleAbbreviation, string ModuleColor, bool ModuleAvailable)
{
this.ModuleName = ModuleName;
this.ModuleAbbreviation = ModuleAbbreviation;
this.ModuleColor = ModuleColor;
this.ModuleAvailable = ModuleAvailable;
}
public string ModuleName { get; set; }
public string ModuleAbbreviation { get; set; }
public string ModuleColor { get; set; }
public bool ModuleAvailable { get; set; }
}
ViewModel code is below (it has been shortened, the relevant code for the Module List has been included):
namespace Users.ViewModel
{
public class AllUsersViewModel
{
public List<Module> _modules = new List<Module>();
#region Constructor
public AllUsersViewModel()
{
this.SetModuleList();
this.CreateAllUsers();
}
void SetModuleList()
{
_modules = ModuleRepository.GetModules();
}
public IEnumerable<Module> Modules
{
get { return _modules; }
}
void CreateAllUsers()
{
List<UserViewModel> all =
(from cust in _userRepository.GetUsers()
select new UserViewModel(cust, _userRepository)).ToList();
foreach (UserViewModel cvm in all)
cvm.PropertyChanged += this.OnUserViewModelPropertyChanged;
this.AllUsers = new ObservableCollection<UserViewModel>(all);
this.AllUsers.CollectionChanged += this.OnCollectionChanged;
}
public ObservableCollection<UserViewModel> AllUsers { get; private set; }
....
}
}
Following is the XAML: (A bit further than half way you'll see a ListBox called lstModules)
<UserControl.Resources>
<CollectionViewSource x:Key="UserCollection" Source="{Binding Path=AllUsers}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Name" Direction="Ascending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<DataGrid AutoGenerateColumns="False" ItemContainerStyle="{StaticResource UserItemStyle}" AlternatingRowBackground="{x:Null}" ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
<DataGridTextColumn Header="Job Title" Binding="{Binding Path=Job_Title}"/>
<DataGridTextColumn Header="Department" Binding="{Binding Path=Department}"/>
<DataGridTextColumn Header="Company" Binding="{Binding Path=Company}"/>
<DataGridTextColumn IsReadOnly="True" Binding="{Binding Path=Company}" CanUserResize="False" Width="580">
<DataGridTextColumn.Header>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<TextBlock HorizontalAlignment="Center">Modules</TextBlock>
<ListBox x:Name="lstModules" Width="190" ItemsSource="{Binding Modules}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ModuleName}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Header="Contact Detail" Binding="{Binding Path=Name}"/>
</DataGrid.Columns>
</DataGrid>
[Edit] Full XAML
<UserControl x:Class="Users.View.AllUsersView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="160" d:DesignWidth="1100">
<UserControl.Resources>
<CollectionViewSource x:Key="UserCollection" Source="{Binding Path=AllUsers}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Name" Direction="Ascending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<Style x:Key="UserItemStyle" TargetType="{x:Type DataGridRow}">
<!--
Stretch the content of each cell so that we can
right-align text in the Total Sales column.
-->
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<!--
Bind the IsSelected property of a ListViewItem to the
IsSelected property of a UserViewModel object.
-->
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<!--
<Condition Property="ItemsControl.AlternationIndex" Value="1" />
-->
<Condition Property="IsSelected" Value="False" />
<Condition Property="IsMouseOver" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="#EEEEEEEE" />
</MultiTrigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="headerTemplate">
<TextBlock Padding="0,0,0,0" Margin="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Bottom" Text="{Binding}"/>
</DataTemplate>
<Style x:Key="RowHeaderStyle2" TargetType="DataGridRowsPresenter">
<Setter Property="Background" Value="{x:Null}"/>
</Style>
<Style x:Key="ColumnHeaderStyle" TargetType="DataGridColumnHeader">
<Setter Property="VerticalContentAlignment" Value="Bottom"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Height" Value="25"/>
</Style>
<Style x:Key="ModuleColumnHeaderStyle" TargetType="GridViewColumnHeader">
<Setter Property="VerticalContentAlignment" Value="Bottom"/>
<Setter Property="Width" Value="550"/>
</Style>
<Style x:Key="rotatedTextStart" TargetType="TextBlock">
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="-45" />
</Setter.Value>
</Setter>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Width" Value="130"/>
<Setter Property="Margin" Value="12,0,0,0"/>
</Style>
<Style x:Key="rotatedTextMiddle" TargetType="TextBlock">
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="-45" />
</Setter.Value>
</Setter>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Width" Value="130"/>
<Setter Property="Margin" Value="-50,0,0,0"/>
</Style>
<Style x:Key="rotatedTextEnd" TargetType="TextBlock">
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="-45" />
</Setter.Value>
</Setter>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Width" Value="130"/>
<Setter Property="Margin" Value="-50,0,12,0"/>
</Style>
<Style x:Key="ListViewItemRotatedText" TargetType="ListViewItem">
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="-45" />
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<DockPanel>
<Grid DockPanel.Dock="Bottom" Margin="0,2,4,2">
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="Selected Users: " />
<ContentPresenter Content="{Binding Path=TotalSelectedUsers}" ContentStringFormat="0" />
<TextBlock Text=" of " />
<ContentPresenter Content="{Binding Path=TotalUsers}" ContentStringFormat="0" />
</StackPanel>
</Grid>
<DataGrid AutoGenerateColumns="False" ItemContainerStyle="{StaticResource UserItemStyle}" AlternatingRowBackground="{x:Null}" DataContext="{StaticResource UserCollection}" ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" IsReadOnly="True" HeaderStyle="{StaticResource ColumnHeaderStyle}" HeaderTemplate="{StaticResource headerTemplate}" Binding="{Binding Path=Name}"/>
<DataGridTextColumn Header="Job Title" IsReadOnly="True" HeaderStyle="{StaticResource ColumnHeaderStyle}" HeaderTemplate="{StaticResource headerTemplate}" Binding="{Binding Path=Job_Title}"/>
<DataGridTextColumn Header="Department" IsReadOnly="True" HeaderStyle="{StaticResource ColumnHeaderStyle}" HeaderTemplate="{StaticResource headerTemplate}" Binding="{Binding Path=Department}"/>
<DataGridTextColumn Header="Company" IsReadOnly="True" HeaderStyle="{StaticResource ColumnHeaderStyle}" HeaderTemplate="{StaticResource headerTemplate}" Binding="{Binding Path=Company}"/>
<DataGridTextColumn IsReadOnly="True" Binding="{Binding Path=Company}" CanUserResize="False" Width="580">
<DataGridTextColumn.Header>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<TextBlock HorizontalAlignment="Center">Modules</TextBlock>
<ListBox x:Name="lstModules" Width="190" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Modules}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ModuleName}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Header="Contact Detail" IsReadOnly="True" HeaderStyle="{StaticResource ColumnHeaderStyle}" HeaderTemplate="{StaticResource headerTemplate}" Binding="{Binding Path=Name}"/>
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</UserControl>
The ListBox belongs to DataGrid control, which has it's own DataContext (AllUsers), which doesn't have Modules property. You should get Modules from UserControl's DataContext:
<ListBox x:Name="lstModules" Width="190"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl}},
Path=DataContext.Modules}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ModuleName}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Which Event is fired after all row has been sorted in wpf data grid.

In my WPF DataGrid , I have a problem while sorting the row.
I am setting the new Style from code behind , while datagrid loaded event Name .
But when i click on the Header for the sorting my DataGrid Style changes to the default.
My code for DataGrid :-
<DataGrid x:Name="dtstandardview" BorderThickness="0" Height="429" Width="688" BorderBrush="Aqua" MouseLeftButtonDown="dtstandardview_MouseRightButtonUp_1"
GridLinesVisibility="None" MouseRightButtonUp="dtstandardview_MouseRightButtonUp_1"
VerticalScrollBarVisibility="Visible" AutoGenerateColumns="False" IsReadOnly="True"
CanUserDeleteRows="False" AlternationCount="2" CanUserResizeRows="False" Sorting="dtstandardview_Sorting_1"
Background="#DCDCDC" HeadersVisibility="Column" CanUserResizeColumns="False"
RowHeight="27" SelectionUnit="FullRow" CanUserAddRows="False" MinRowHeight="27" LoadingRow="dtstandardview_LoadingRow" LoadingRowDetails="dtstandardview_LoadingRowDetails" Loaded="dtstandardview_Loaded" Initialized="dtstandardview_Initialized" CellEditEnding="dtstandardview_CellEditEnding" AutoGeneratingColumn="dtstandardview_AutoGeneratingColumn" UnloadingRow="dtstandardview_UnloadingRow" UnloadingRowDetails="dtstandardview_UnloadingRowDetails" >
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="0" Color="#FF000000" Direction="-60" Opacity="0.32" ShadowDepth="1"/>
</Setter.Value>
</Setter>
<Setter Property="Margin" Value="10,5" />
<Setter Property="VerticalContentAlignment" Value="Bottom"/>
</Style>
</DataGrid.CellStyle>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="Foreground" Value="#404040"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="DataContext">
<Setter.Value>
<TextBlock Margin="10,0,0,0" TextWrapping="Wrap" Text="{Binding}">
<TextBlock.Effect>
<DropShadowEffect BlurRadius="0" Color="#FF000000" Direction="-60" Opacity="0.32" ShadowDepth="1"/>
</TextBlock.Effect>
</TextBlock>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
<DataGrid.RowBackground >
<ImageBrush ImageSource="/ClientApplication;component/Images/second_row_bg.png"/>
</DataGrid.RowBackground>
<DataGrid.AlternatingRowBackground>
<ImageBrush ImageSource="/ClientApplication;component/Images/bonus_progress_bg.png"/>
</DataGrid.AlternatingRowBackground>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<TextBlock Foreground="#404040" FontWeight="Bold" Margin="10,0,0,0" TextWrapping="Wrap" Text="{Binding}" TextOptions.TextFormattingMode="Display">
<TextBlock.Effect>
<DropShadowEffect BlurRadius="0" Color="#FFFFFF" Direction="-90" Opacity="0.40" ShadowDepth="1" RenderOptions.ClearTypeHint="Auto" />
</TextBlock.Effect>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="/ClientApplication;component/Images/table_bg_header.png"/>
</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>
<ImageBrush ImageSource="/ClientApplication;component/Images/titel_bg.png"/>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="#404040" />
<Setter Property="BorderThickness" Value="0, 0, 1, 0"/>
<Setter Property="Height" Value="26" />
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontFamily" Value="Arial"/>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridTextColumn Width="125" Header="Table" Binding="{Binding Path=Table}">
</DataGridTextColumn>
<DataGridTextColumn Width="101" Header="Stakes" Binding="{Binding Path=Stakes}" />
<DataGridTextColumn Width="95" Header="Game" Binding="{Binding Path=Game}" />
<DataGridTemplateColumn Header="Type" Width="86">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:Name="typedatatempl">
<StackPanel Orientation="Horizontal" Name="stackpaneltype">
<TextBlock Name="typedate" Text="{Binding Path=Type}" Margin="2,0,0,2" />
<TextBlock Name="txtblocknumber" Text="{Binding Path=number}" Margin="2, 0, 0, 2" Background="Gray" TextAlignment="Center" FontFamily="Arial" FontWeight="Bold" FontSize="10" Foreground="White" Height="13" Width="13" VerticalAlignment="Center" HorizontalAlignment="Center" />
<TextBlock Name="txtblockalpha" Text="{Binding Path=alphabate}" Margin="5,0,0,2" Background="Yellow" FontFamily="Arial" TextAlignment="Center" FontWeight="Bold" FontSize="10" Foreground="White" Height="13" Width="13" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Width="83" Header="Players" Binding="{Binding Path=Players}" />
<DataGridTextColumn Width="117" Header="Average Pot" Binding="{Binding Path=Average}" />
<DataGridTextColumn Width="63" Header="H/Hr" Binding="{Binding Path=hhr}" />
</DataGrid.Columns>
</DataGrid>
dataGrid.xaml.cs
int i = e.Row.GetIndex();
// SetDatGrid();
// to get the all the row one by one.
DataGridRow objrow = new DataGridRow();
DataGridCell objcell = new DataGridCell();
// objrow = ExtensionMethods.GetRow(dtstandardview, i);
objcell = ExtensionMethods.GetCell(dtstandardview, e.Row, 3);
ContentPresenter objcontent = new ContentPresenter();
if (objcell != null)
{
objcontent = (ContentPresenter)objcell.Content;
GameClassTemp objGameClassTemp = new GameClassTemp();
objGameClassTemp = (GameClassTemp)objcontent.Content;
ContentPresenter cp = dtstandardview.ItemContainerGenerator.ContainerFromItem(objcell) as ContentPresenter;
StackPanel objstackpanel = ExtensionMethods.FindVisualChild<StackPanel>((ContentPresenter)objcell.Content);
TextBlock objtypedate = (TextBlock)objstackpanel.FindName("typedate");
TextBlock objtxtblocknumber = (TextBlock)objstackpanel.FindName("txtblocknumber");
TextBlock objtxtblockalpha = (TextBlock)objstackpanel.FindName("txtblockalpha");
if (objGameClassTemp != null)
{
if (objGameClassTemp.alphabate != null && objGameClassTemp.alphabate.Trim().Length > 0)
{
var bc = new BrushConverter();
switch (objGameClassTemp.number)
{
case "1":
objtxtblockalpha.Background = Brushes.Green;
break;
case "2":
objtxtblockalpha.Background = Brushes.Yellow;
break;
case "3":
objtxtblockalpha.Background = Brushes.Red;
break;
case "4":
objtxtblockalpha.Background = (Brush)bc.ConvertFrom("#85ab33");
break;
case "5":
//objtxtblockalpha.Background = Brushes.Pink;
objtxtblockalpha.Background = (Brush)bc.ConvertFrom("#f9572a");
break;
case "6":
objtxtblockalpha.Background = (Brush)bc.ConvertFrom("#e0d921");
break;
default:
objtxtblockalpha.Background = Brushes.YellowGreen;
break;
}
}
else
{
objtxtblockalpha.Background = Brushes.Transparent;
}
}
}
You need to use LoadingDataRow event
dataGrid.LoadingRow += dataGrid_LoadingRow;
void dataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
var dataContext = e.Row.DataContext;
}

TextWrapping textbox in WPF DataGrid

I've been trying to make my textboxes in my DataGrid wrap. I got it working but it seems to break the Text binding.
XAML
<DataGrid x:Name="dataGrid" Grid.Row="0" AutoGenerateColumns="False" ItemsSource="{Binding}">
<!-- <DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<TextBox TextWrapping="Wrap" Text="{Binding Path=Value}">
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.CellStyle> -->
</DataGrid>
I add the columns and rows using a data set like so.
CS
#region Variables
private DataTable m_stringData = new DataTable();
private DataSet m_stringDataSet = new DataSet();
#endregion
#region Constructors
public LocEditor()
{
InitializeComponent();
AddColumn("ID", 100);
AddString("Test");
dataGrid.DataContext = m_stringData;
}
#endregion
#region Methods
private void AddColumn(string l_columnName, int l_iWidth)
{
m_stringData.Columns.Add(l_columnName, typeof(string));
dataGrid.Columns.Add(new DataGridTextColumn
{
Header = l_columnName,
Width = l_iWidth,
Binding = new Binding(l_columnName)
//Binding = new Binding(string.Format("[{0}]", l_columnName))
});
}
private void AddString(string l_stringID)
{
m_stringData.Rows.Add();
m_stringData.Rows[m_stringData.Rows.Count - 1][0] = l_stringID;
}
#endregion
Any help would be greatly appreciated.
Figured it out. By setting the Element and EditingElementStyle, I don't have to reset the Binding.
DataGridTextColumn l_column = new DataGridTextColumn();
l_column.Header = l_columnName;
l_column.Binding = new Binding(l_columnName);
l_column.Width = l_iWidth;
Style l_textStyle = new Style(typeof(TextBlock));
l_textStyle.Setters.Add(new Setter(TextBlock.TextWrappingProperty, TextWrapping.Wrap));
l_column.ElementStyle = l_textStyle;
Style l_textEditStyle = new Style(typeof(TextBox));
l_textEditStyle.Setters.Add(new Setter(TextBox.TextWrappingProperty, TextWrapping.Wrap));
l_column.EditingElementStyle = l_textEditStyle;
dataGrid.Columns.Add(l_column);
This inserts the GridViewColumn directly into the GridView, but it worked for me.
<ListView Name="myListView">
<ListView.View>
<GridView>
<GridViewColumn Header="HEADER NAME" x:Name="header">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox TextWrapping="Wrap" Text="{Binding Path=Value}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
In order to see the wrapped text fully, you will need to set the height of the rows to be large enough to see this (or do height conversions dynamically).
<My:ToHeightConverter x:Key="heightConverter" />
<Style TargetType="ListViewItem">
<Setter Property="Height" Value="{Binding ElementName=myListView, Path=ActualHeight, Converter={StaticResource heightConverter}}" />
</Style>
And then in the code behind the GridView:
[ValueConversion(typeof(double), typeof(double))]
public class ToHeightConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return (((double)value * 10); //return the height wanted here
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
If you're looking to just add TextWrapping to all TextBoxes in your DataGrid, I would suggest making an implicit style for them in your DataGrid.Resources
<DataGrid.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</DataGrid.Resources>
The reason why the data isn't showing up in your Template is because you're missing the ContentPresenter. This is the object that displays the rendered content of the actual DataGridCell. The DataGridCell itself has no idea what the content of its cell is, so doesn't know what the binding is.
For example, this works
<Style TargetType="DataGridCell">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<TextBlock TextWrapping="Wrap">
<ContentPresenter Content="{TemplateBinding Content}" />
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But not this
<Style TargetType="DataGridCell">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<TextBox TextWrapping="Wrap" Text="{TemplateBinding Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
because the Content is whatever object happens to be in the cell at the time, whether it is a TextBox, TextBlock, ComboBox, etc

Categories

Resources