I'm creating a file explorer app using the TreeView control provided by WPF. I've customized it such that it displays a file icon next to the path. I'm using a IValueConverter to convert the path to the required image, which I based off this page: http://www.codeproject.com/Articles/21248/A-Simple-WPF-Explorer-Tree
It mostly works! Except that the root TreeViewItems don't display icons for some reason. I placed a breakpoint on the IValueConverter::Convert() function and confirmed that it doesn't get executed for the root nodes, but do for all children nodes after that.
The VS output window shows no binding errors, so I'm at a loss at how this could happening. Any ideas?
Converter Code:
[ValueConversion(typeof(string), typeof(bool))]
public class HeaderToImageConverter : IValueConverter
{
public static HeaderToImageConverter Instance = new HeaderToImageConverter();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((value as string).Contains(#"\"))
{
Uri uri = new Uri("pack://application:,,,/Images/diskdrive.png");
BitmapImage source = new BitmapImage(uri);
return source;
}
else
{
Uri uri = new Uri("pack://application:,,,/Images/folder.png");
BitmapImage source = new BitmapImage(uri);
return source;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException("Cannot convert back");
}
}
TreeView XAML:
<TreeView Grid.Column="0" Name="fileExplorer" Margin="8,8,8,8">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="20" Height="20" Stretch="Fill" Source="{Binding Converter={x:Static local:HeaderToImageConverter.Instance}}" />
<TextBlock Text="{Binding}" Margin="5,0" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
I ran into a similar problem. But besides the TreeView.Resources I had the TreeView.ItemContainerStyle element as well. Moving the Style element to there actually styled only the root, but not the children. Therefore, a solution would be to put the element in both places.
TreeView XAML:
<TreeView Grid.Column="0" Name="fileExplorer" Margin="8,8,8,8">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="20" Height="20" Stretch="Fill" Source="{Binding Converter={x:Static local:HeaderToImageConverter.Instance}}" />
<TextBlock Text="{Binding}" Margin="5,0" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="20" Height="20" Stretch="Fill" Source="{Binding Converter={x:Static local:HeaderToImageConverter.Instance}}" />
<TextBlock Text="{Binding}" Margin="5,0" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
Now, it would be nicer not to have to reuse this HeaderTemplate Setter. But I have not found a way to do this.
Related
I have three buttons inside ListView.
I tried to click each of the button, however the ItemClick function was not triggered.
There is the xaml file of the ListView
<UserControl.Resources>
<DataTemplate x:Name="DefaultWideSideItemTemplate" x:DataType="ui:AppMenuItem">
<Grid>
<ui:ButtonWithIcon IconContent="{x:Bind Icon}"
Content="{x:Bind Name}"
Style="{StaticResource TransparentFontButtonStyle}"
/>
</Grid>
</DataTemplate>
<others:SideMenuItemTemplateSelector DefaultTemplate="{StaticResource DefaultWideSideItemTemplate}" x:Key="WideSideItemTemplateSelector"/>
</UserControl.Resources>
<ListView Style="{StaticResource HorizontalCenterListView}"
IsItemClickEnabled="True"
ItemsSource="{x:Bind MenuItemCollection}"
VerticalAlignment="Top"
x:Name="SideMenuListView"
Loaded="SideMenuListView_Loaded"
ItemClick="SideMenuListView_ItemClick"
ItemTemplateSelector="{StaticResource WideSideItemTemplateSelector}">
</ListView>
There is the code where ItemClick was defined.
public event EventHandler<AppMenuItem> SideMenuItemClick;
private void SideMenuListView_ItemClick(object sender, ItemClickEventArgs e)
{
// DO SOMETHING HERE
}
There is the xaml file of the ui:ButtonWithIcon
<Style x:Key="TransparentFontButtonStyle" TargetType="ui:ButtonWithIcon">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="FontSize" Value="30"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,32,0,7"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ui:ButtonWithIcon">
<StackPanel>
<TextBlock
x:Name="IconContent"
Text="{Binding IconContent, RelativeSource={RelativeSource TemplatedParent}}"
HorizontalAlignment="Center"
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="30"/>
<TextBlock
x:Name="Text"
Text="{TemplateBinding Content}"
HorizontalAlignment="Center"
FontSize="14"
Margin="0,10,0,0"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
What did I understand wrong about ListView? Buttons can not be used in ListView?
Update: ButtonWithIcon
public class ButtonWithIcon : Button
{
public static readonly DependencyProperty IconContentProperty =
DependencyProperty.Register("IconContent", typeof(string), typeof(ButtonWithIcon), new PropertyMetadata(default));
public string IconContent
{
get { return (string)GetValue(IconContentProperty); }
set { SetValue(IconContentProperty, value); }
}
}
Update 2:
<DataTemplate x:Name="DefaultWideSideItemTemplate" x:DataType="ui:AppMenuItem">
<Grid>
<StackPanel Margin="0,32,0,7">
<TextBlock Text="{x:Bind Icon}"
HorizontalAlignment="Center"
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="30"/>
<TextBlock
Text="{x:Bind Name}"
HorizontalAlignment="Center"
Margin="0,10,0,0"
FontSize="14"/>
</StackPanel>
</Grid>
</DataTemplate>
If the ui:ButtonWithIcon is a custom button control, then this is expected behavior. When you click on the custom button, the click event is captured by the button, so the ListView won't trigger the ItemClick event. A simple way to confirm is that you could click on the place that does not belong to the custom button. It should fire the ItemClick event of the ListView.
Update:
Since your code is too messy, I made a simple test using some of your code:
<ListView HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
IsItemClickEnabled="True"
ItemsSource="{x:Bind MenuItemCollection}"
x:Name="SideMenuListView"
Loaded="SideMenuListView_Loaded"
ItemClick="SideMenuListView_ItemClick"
>
<ListView.ItemTemplate>
<DataTemplate >
<Grid>
<StackPanel Margin="0,32,0,7">
<TextBlock
Text="{Binding}"
HorizontalAlignment="Center"
Margin="0,10,0,0"
FontSize="14"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This works correctly.
You could remove the extra parts of your code to narrow down the issue. Start with a easy sample like the above.
I have the following TabConrol
<telerik:RadTabControl
Grid.Row="2" VerticalAlignment="Top" SelectedIndex="{Binding SelectedIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Content" DropDownDisplayMode="Visible" ScrollMode="Item" BorderThickness="0">
<telerik:RadTabItem DropDownContent="Job Config" Header="Job Config" >
<telerik:RadTabItem.Content>
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<local:JobGroupsCars DataContext="{Binding}" Margin="10" IsEnabled="{Binding Job.IsNotInEditMode ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</ScrollViewer>
</telerik:RadTabItem.Content>
</telerik:RadTabItem>
<telerik:RadTabItem
DropDownContent="Job Info" Header="Job Info" >
<telerik:RadTabItem.Content>
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<local:JobDetailView DataContext="{Binding}" Margin="10" IsEnabled="{Binding Job.IsNotInEditMode ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</ScrollViewer>
</telerik:RadTabItem.Content>
</telerik:RadTabItem>
<-- more tabs go here -->
</telerik:RadTabControl>
As you can see, the TabItem is a user control
What Im trying to achieve is when I click the save button I want to show the name that has validation errors
Im able to get all the validation errors but Im not able to show which tab has this error (as you can see in the below image)
I tried to use the following snippet but its not working
<UserControl.Resources>
<ControlTemplate x:Key="ValidationTabTemplate">
<DockPanel LastChildFill="True">
<Image Width="32" Height="32"
Source="../Assets/Delete_Icon.png" Opacity="0.75"
ToolTip="{Binding Path=AdornedElement.ToolTip, RelativeSource={RelativeSource AncestorType={x:Type Adorner}, Mode=FindAncestor}}"
/>
<AdornedElementPlaceholder/>
</DockPanel>
</ControlTemplate>
<Style x:Key="CustomTabError" TargetType="{x:Type telerik:RadTabItem}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="HeaderTemplate"
Value="{StaticResource ValidationTabTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
I am using WPF with MVVM
Any help would be appreciated
thanks alot
Okay a little more detailed than my comment:
You want to highight the Tabcontrol that containes your error if i understand you correctly:
Imagine this beeing your tabcontrol and the Checkboxes beeing your input fields we bound our tab item to each of our checkboxes.IsChecked via Multibinding
this would be your custom control and the .Validation.HasError property
if any of the CheckBoxes is not checked ( or in your case if an error occoured) the forground of the tabcontrol will become red by using a multiconverter
<TabControl>
<TabItem Header="Test">
<TabItem.Foreground>
<MultiBinding Converter="{StaticResource MultiEval}">
<Binding ElementName="CB1" Path="IsChecked"/>
<Binding ElementName="CB2" Path="IsChecked"/>
<Binding ElementName="CB3" Path="IsChecked"/>
</MultiBinding>
</TabItem.Foreground>
<StackPanel>
<CheckBox Name="CB1"></CheckBox>
<CheckBox Name="CB2"></CheckBox>
<CheckBox Name="CB3"></CheckBox>
</StackPanel>
</TabItem>
<Window.Resources>
<loc:MultiEvaluator x:Key="MultiEval"/>
</Window.Resources>
Converter:
public class MultiEvaluator : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
foreach (var value in values)
{
if (!System.Convert.ToBoolean(value))
{
return Brushes.Red;
}
}
return Brushes.Black;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I have the following XAML code that represents a TextBox with validation, when an error occurs then the margin is increased so that the message is not overlapping other UI elements under this TextBox.
In XAML every part of this works like I intended for it to work.
Validation is implemented using the IDataErrorInfo interface
<TextBox
Grid.Column="1"
Validation.ErrorTemplate="{StaticResource validationErrorTemplate}"
Style="{StaticResource baseMargins}"
Margin="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.HasError), Converter={StaticResource MarginConv}}"
Padding="{StaticResource basePadding}">
<TextBox.Text>
<Binding
Path="Email"
Mode="TwoWay"
UpdateSourceTrigger="PropertyChanged"
ValidatesOnDataErrors="True"/>
</TextBox.Text>
</TextBox>
Now I want the create the same but at runtime. The page has an ItemsControl that I fill with the generated TextBoxes.
The following code shows how I create this TextBox
private static void CreateForStackOverflow()
{
TextBox textBox = new TextBox();
Binding textBinding = new Binding();
textBinding.Path = new PropertyPath("Email");
textBinding.Mode = BindingMode.TwoWay;
textBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
textBinding.ValidatesOnDataErrors = true;
textBinding.NotifyOnValidationError = true;
textBox.SetBinding(TextBox.TextProperty, textBinding);
var valTemplate = (ControlTemplate)Application.Current.FindResource("validationErrorTemplate");
Validation.SetErrorTemplate(textBox, valTemplate);
Binding valBinding = new Binding();
valBinding.RelativeSource = new RelativeSource(RelativeSourceMode.Self);
valBinding.Path = new PropertyPath("Validation.HasError");
valBinding.Converter = new Converters.BoolMarginConverter();
textBox.SetBinding(FrameworkElement.MarginProperty, valBinding);
}
Now the validation works, errors are created but the only thing that does not work is the Binding for the MarginProperty. This is never triggered.
The following error is displayed in the Output window:
BindingExpression path error: 'Validation' property not found on 'object' ''TextBox' (Name='')'. BindingExpression:Path=Validation.HasError;
DataItem='TextBox' (Name='');
target element is 'TextBox' (Name='');
target property is 'Margin' (type 'Thickness')
I have found it could maybe have something to do with my `DataContext] but it is set in the XAML, and setting that Context was the solution for all those people but not for me.
Using Snoop (2.10.0.0) I can see that the TextBox has a Validation property.
Here is what Snoop shows on the Marginproperty.
This a what the overlapping errors look like.
And the code for the BoolMarginConverter is the following:
public class BoolMarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool hasError = (bool)value;
return hasError ? new Thickness(2, 2, 2, 20) : new Thickness(2, 2, 2, 2);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
But this is never executed because the Validation.HasError could not be found.
What am I missing here?
EDIT: The error template
<ControlTemplate x:Key="validationErrorTemplate">
<DockPanel>
<StackPanel
Orientation="Horizontal" DockPanel.
Dock="Bottom"
ClipToBounds="True">
<Grid
Width="12"
Height="12">
<Ellipse
Width="12"
Height="12"
Fill="Red"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBlock
Foreground="White"
FontWeight="Heavy"
FontSize="8"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center"
Text="X"
ToolTip="{Binding ElementName=ErrorAdorner, UpdateSourceTrigger=PropertyChanged,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Grid>
<TextBlock
Foreground="Red"
FontWeight="Bold"
TextWrapping="NoWrap"
TextTrimming="WordEllipsis"
Margin="2,0,0,0"
Text="{Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors), Converter=converters:ValidationErrorsToStringConverter}}"
/>
</StackPanel>
<AdornedElementPlaceholder x:Name="ErrorAdorner"/>
</DockPanel>
</ControlTemplate>
I was missing the brackets on (Validation.HasError) ...
Validation.HasError ==> (Validation.HasError)
valBinding.Path = new PropertyPath("(Validation.HasError)");
Maybe someday this will help someone.
Thanks all
I wouldn't use code to do all that and even then what you have seems over complicated.
The below markup works for me.
I have a public Int property in code behind just to test by typing a character.
Obviously, if you want to apply this by code then put an x:Key on your style and then you can go grab it out resources and apply it. Mine applies to all textboxes. I don't really follow why you wouldn't want that anyhow.
I would also suggest that moving ui around like this is limiting. I'd prefer a border and outline colour change and see all the errors in a tooltip. You can only fit one this way.
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
<Window.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel>
<StackPanel
Orientation="Horizontal" DockPanel.Dock="Bottom"
ClipToBounds="True">
<Grid
Width="12"
Height="12">
<Ellipse
Width="12"
Height="12"
Fill="Red"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBlock
Foreground="White"
FontWeight="Heavy"
FontSize="8"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center"
Text="X"
ToolTip="{Binding ElementName=ErrorAdorner, UpdateSourceTrigger=PropertyChanged,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Grid>
<TextBlock
Foreground="Red"
FontWeight="Bold"
TextWrapping="NoWrap"
TextTrimming="WordEllipsis"
Margin="2,0,0,0"
Text="{Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors)/ErrorContent}"
/>
</StackPanel>
<AdornedElementPlaceholder x:Name="ErrorAdorner"/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)/ErrorContent}"/>
<Setter Property="Margin" Value="0,0,0,20"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<TextBox Text="{Binding MyNum, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="Banana"/>
<Button Content="Some Button"/>
</StackPanel>
</Grid>
I have the following ControlTemplate for the Validation of a ComboBox
<ControlTemplate x:Key="ComboBoxHighlightTemplate" TargetType="Control">
<Grid ClipToBounds="False">
<Border BorderBrush="{StaticResource fokusBrush}" BorderThickness="2.5" Margin="-1" Visibility="{Binding ElementName=adornedElementHighligh,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent, Converter={StaticResource inverseErrorContentVisibilityConverter}}">
<AdornedElementPlaceholder Name="adornedElementHighligh"/>
</Border>
<Border BorderBrush="Red" BorderThickness="1" Margin="-1" Visibility="{Binding ElementName=adornedElement,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent, Converter={StaticResource errorContentToErrorVisibilityConverter}}">
<AdornedElementPlaceholder Name="adornedElement" />
</Border>
<Image HorizontalAlignment="Right" VerticalAlignment="Top" Visibility="{Binding ElementName=adornedElement,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent, Converter={StaticResource errorContentToErrorVisibilityConverter}}"
Width="16" Height="16" Margin="0,-9,-9,0" Source="{x:Static helper:ImageHelper.ErrorImage}"
ToolTip="{Binding ElementName=adornedElement, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Grid>
</ControlTemplate>
Depending on the ErrorContent I decide which Border I draw around the ComboBox.
The Converter ErrorContentToErrorVisibilityConverter looks like
internal class ErrorContentToErrorVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string)
{
if (((string) value).EndsWith("not an error"))
return Visibility.Hidden;
}
return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Everything just works fine. But if I produce an error in my ComboBox so that the ControlTemplate for Errors is shows, the bounds of the drawn borders are not at the "real" borders of the ComboBox.
The usage of the ControlTemplate looks like:
here is a sample template, I did try to simplify it for you
<ControlTemplate x:Key="ComboBoxHighlightTemplate"
TargetType="Control">
<Grid ClipToBounds="False">
<AdornedElementPlaceholder Name="adornedElement" />
<Border BorderBrush="Red"
BorderThickness="1"
x:Name="errorBorder" />
<Image HorizontalAlignment="Right"
VerticalAlignment="Top"
x:Name="image"
Width="16"
Height="16"
Margin="0,-9,-9,0"
Source="{x:Static helper:ImageHelper.ErrorImage}"
ToolTip="{Binding ElementName=adornedElement, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding AdornedElement.(Validation.Errors)[0].ErrorContent, ElementName=adornedElement,Converter={StaticResource errorContentToErrorVisibilityConverter}}"
Value="Hidden">
<Setter Property="BorderBrush"
TargetName="errorBorder"
Value="{StaticResource fokusBrush}" />
<Setter Property="BorderThickness"
TargetName="errorBorder"
Value="2.5" />
<Setter Property="Visibility"
TargetName="image"
Value="Collapsed" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
try it and let me know how close is this to your results, we may also simplify the trigger a bit further, I did this on assumptions.
I have a listview which is Grouped by Properties of the underlying Datasource.
The Groupstyle contains a Expander with an Header in which I want to display various things.
The listview shows Emails which are for example grouped by subject.
I know want to display (UnreadMailCount/Items) in each Group Header.
My Solution so far is:
<ListView Name="Mails" local:FM.Register="{Binding}" local:FM.GetFocus="Loaded"
Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
ItemsSource="{Binding Path=MailsProxy.View}"
SelectionMode="Single" SelectedItem="{Binding Path=SelectedMail, Mode=TwoWay}"
local:SortList.BringIntoViewSelected="True" local:SortList.IsGridSortable="True"
ItemContainerStyle="{StaticResource InboxMailItem}"
View="{Binding Source={x:Static session:Session.Current}, Path=InboxView.View}">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander Foreground="Black" BorderThickness="0,0,0,1" Style="{StaticResource ExpanderStyle}" Expanded="OnExpand" Collapsed="OnCollapse" Loaded="OnLoad">
<Expander.Header>
<DockPanel>
<TextBlock FontSize="14" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListView}, Path=DataContext.GroupBy}"/>
<TextBlock FontSize="14">:</TextBlock>
<TextBlock FontSize="14" Text="{Binding Path=Name, Converter={StaticResource GroupHeaderConverter}}" Margin="5,0,0,0"/>
<TextBlock> </TextBlock>
<TextBlock FontSize="14" Margin="0,1,0,0">(</TextBlock>
<TextBlock FontSize="14" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListView}, Path=DataContext.Unread}"/>
<!--<TextBlock FontSize="14" Text="{Binding StringFormat=0, Converter={StaticResource InboxGroupSeenConverter}}" />-->
<TextBlock FontSize="14">/</TextBlock>
<TextBlock FontSize="14" Text="{Binding Path=ItemCount}"/>
<TextBlock FontSize="14">)</TextBlock>
</DockPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
<ListView.Resources>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="DataContext" Value="{Binding Source={x:Static session:Session.Current}, Path=InboxView}"/>
</Style>
</ListView.Resources>
</ListView>
As you can see i tried to display the unread Mailitems by using a converter ( -->) this works, except, that the Header is not updated after the Property of the Mailitem is changed.
The Converter:
public class InboxGroupSeenConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return GetTotalUnread(value as CollectionViewGroup);
}
private static int GetTotalUnread(CollectionViewGroup group)
{
int count = 0;
foreach (eMail mailItem in group.Items)
if (mailItem.Seen == false)
count++;
return count;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Is there a way to do this with the Converter or should I go a different way by using Properteis as seen above ()
Edit: To clarify my Question. The Header of My group displays must display two different numbers. One being the ItemCount of the Group, the second being the number of Unread items within this group.
The number of unread Items is calculated within my converter which was a test for me, however this solution does not update the view if the underlying collection properties change.
I think that your Expander needs DynamicResource Style.
BTW Expander has it's own properties which you can use for your solution here is an example in the question I answered before
WPF-ListView-GridView-allow users...
good luck and let us know :-)
EDIT
tomorrow I'll come back to you, as I am finishing work soon :-), remember that expander has it's own itemsCount so there is no need to implement your own, second thing is to implement in your email object property bool Unread than just bind it to your textblock style using DataTriggers and voila!