Expander inside ListViewItem - wpf

I have a listview for which i have implemented grouping and have defined an expander inside the groupstyle as shown below :
<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 IsExpanded="True" >
<Expander.Header>
<DockPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5,0,0,0" Width="100"/>
<TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
<TextBlock FontWeight="Bold" Text=" Items"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
I want to modify the expander such that only one is expanded and the rest are collapsed if more than one are there and also if i want to programmatically expand any one of the expanders i.e. suppose i add an object from cs and want to show that expander opened, it should be possible, any suggestions ??
Thanks in advance
Edit : The code to bind the listview and the group :
CollectionViewSource viewSource = new CollectionViewSource { Source = TO_DOlst };
viewSource.GroupDescriptions.Add(new PropertyGroupDescription("timeCategory"));
lstView.ItemsSource = viewSource.View;
timecategory is a member of the class

You can Bind IsExpanded property by creating a boolean property in your class just like Name and define all Business rules in CS directly.
if(ItemsSource.Count() > 1)
//set IsExpanded = false;
else
// set only first item and so on.
Regards.

Related

Why does setting ListView.View blow away my custom ControlTemplate?

I have a custom control that inherits from ListView. I've defined a custom template for it and it works the way it's supposed to. However, when I define a view for my list view the custom template does not seem to be applied.
Here's what I'm doing:
My control:
public class TestListView : ListView
{
static TestListView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TestListView), new FrameworkPropertyMetadata(typeof(TestListView)));
}
public TestListView() : base(){}
}
My custom template:
<Style x:Key="{x:Type local:TestListView}" TargetType="{x:Type local:TestListView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListView">
<DockPanel>
<TextBlock Text="foo!" DockPanel.Dock="Top"/>
<ScrollViewer x:Name="PART_ContentScrollViewer" Style="{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}">
<ItemsPresenter />
</ScrollViewer>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My XAML:
<StackPanel>
<GroupBox Header="With View">
<local:TestListView>
<ListViewItem>One</ListViewItem>
<ListViewItem>Two</ListViewItem>
<ListViewItem>Three</ListViewItem>
<local:TestListView.View>
<GridView>
<GridViewColumn Header="MyColumn" />
</GridView>
</local:TestListView.View>
</local:TestListView>
</GroupBox>
<GroupBox Header="With No View">
<local:TestListView>
<ListViewItem>One</ListViewItem>
<ListViewItem>Two</ListViewItem>
<ListViewItem>Three</ListViewItem>
</local:TestListView>
</GroupBox>
</StackPanel>
Here's what happens:
I can get the expected results by explicitly declaring the style (Style="{StaticResource {x:Type local:TestListView}}") or if the style is defined in the same file as the control (not in Generic.xaml or some other resource dictionary).
Can anyone help me understand why this is happening?

Expander Header not display group field content, only ItemsCount

i have a WPF DataGrid with a GroupStyle
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Header>
<StackPanel>
<TextBlock Text="{Binding Path=citta}" Margin="5,0,0,0" Width="100" FontWeight="Bold"/>
<TextBlock Text="{Binding Path=ItemCount}" />
</StackPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
code behind:
var qq = (from a in q select new { formareg = a.Get("formareg"), citta = a.Get("citta"), conteggio = a.Get("conteggio"), parametro = a.Get("idcitta").ToString() + "|" + a.Get("formareg") }).OrderBy(x => x.citta).ToList();
ListCollectionView cv = new ListCollectionView(qq);
cv.GroupDescriptions.Add(new PropertyGroupDescription("citta"));
GrigliaDati.ItemsSource = cv;
All works fine but in Header of each group i see only ItemCount and not Path=citta.
What's wrong??
Same as my earlier answer to this question, it's because you bind to wrong field. You need to bind to group name and not to the field you group by. Try somethink like this:
<TextBlock Text="{Binding Path=Name}">
Each group is a CollectionViewGroup and it has its own properties that you can use when specifying group header.

WPF Bind Visibility of Validation Adorner in MVVM

I am currently working on an MVVM Solution, using WPF Validation.
What I'd like to do is be able to control when the Validation Adorners are shown using a "ShowErrors" Visibility Property in my Context.
I have the following Template for the WPF ComboBox Validation Adorners, contained within my Application.xaml file;
<Style TargetType="{x:Type ComboBox}">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,2,40,2" />
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="true">
<Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
ToolTip="{Binding ElementName=customAdorner1, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
<TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white">
</TextBlock>
</Border>
<AdornedElementPlaceholder Name="customAdorner1" VerticalAlignment="Center" >
<Border BorderBrush="red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
(I have a separate Template for TextBoxes)
After doing some searching on StackOverflow and Google, I tried adding the following to the DockPanel;
Visibility="{Binding DataContext.ShowErrors, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Mode=TwoWay}"
But this doesn't seem to work for me, even though the same method works fine from within the Main XAML.... Any ideas?
EDIT: My UserControl to which I bind my DataContext to has an x:Name of "MainContext"
I found acouple of theads which suggested;
Visibility="{Binding DataContext.ShowErrors, Source={x:Reference Name=MainContext}, Mode=TwoWay}">
Which gives an error of
Unresolved reference 'MainContext'
Aswell as;
Visibility="{Binding DataContext.ShowErrors, ElementName=MainContext, Mode=TwoWay}">
Which just doesn't work.
Edit2: If I move the whole adorner out of the Appliation.xaml and into the UserControl Resources, then use;
Visibility="{Binding DataContext.ShowErrors, ElementName=MainContext, Mode=TwoWay}">
It works... Not ideal though, as I don't want to have to repeat the Template across all my Screens
Edit 3: Ok, so I've found a workaround for now. I used the following for the Visibility Binding...
Visibility="{Binding ElementName=customAdorner1, Path=AdornedElement.Parent.DataContext.ShowErrors, Converter={StaticResource MyBolVisibilityConverter}, Mode=TwoWay}"
I then added a Boolean ShowErrors Property to the context and added a Converter to convert from the Boolean Value to a Visibility Value, mainly because of where the ShowErrors Property actually ended up.
This was slightly more confusing as my Form is a Master Details arrangement, where the Adorners are shown within the details section, which has it's own DataContext. This, of course, doesn't have access to the UserControl's DataContext directly.
This seems like a bit of a hack to me really, so I would appreciate a better solution!
I solved this by adding a ShowErrors Boolean Property to my DataContext, then Binding the Adorner Visibility to the AdornedElement's Parents DataContext, which of course if my known DataContext.
I used the following XAML in my Application.xaml file;
<Converters:BolVisibilityConverter x:Key="MyBolVisibilityConverter"/>
<Style TargetType="{x:Type TextBox}">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,2,40,2" />
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="true" Visibility="{Binding ElementName=customAdorner, Path=AdornedElement.Parent.DataContext.ShowErrors, Converter={StaticResource MyBolVisibilityConverter}, Mode=TwoWay}">
<Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
<TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white">
</TextBlock>
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
<Border BorderBrush="red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I used the following Converter Code;
Namespace Converters
Public Class BolVisibilityConverter
Implements IValueConverter
Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.Convert
If value Is Nothing OrElse value = False Then
Return Visibility.Hidden
Else
Return Visibility.Visible
End If
End Function
Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
Return DirectCast(value, Boolean)
End Function
End Class
End Namespace
I then simply set the ShowErrors Property in my DataContext, to either True or False in order to Show or Hide the Adorners.
This was very useful, as the Adorners always appear on the very top layer, and so show up over the top of Custom Dialog boxes etc.

Data Binding with Silverlight accordion Control

I have Silverlight Accordion control in the ChildWindow and I customized it the following way
<Style x:Key=itemStyle TargetType=AccordionItem>
<Setter Porperty=HeaderTemplate>
<DataTemplate>
<TextBlock x:Name=_headertext/>
</DataTemplate>
</Setter>
</Style>
<Accordion Style"{StaticResource itemStyle}">
<Accordion.ContentTemplate>
<DataTemplate>
<StackPanel>
<CheckBox/>
<TextBlock x:name=_contenttext/>
</DataTemplate>
<Accordion.ContentTemplate>
</Accordion>
Now I have a method in my Chilwindow.Xaml
public void LoadItems(ObservableColection<Groups> gp)
{}
This method is called from the mainpage and it passes the gp value
Groups is a class with public properties and Observable collections.For example
public class Groups
{
public string FirstName{get, set;}
public ObservableCollection<Details> details {get, set;}
public Groups()
{
this.details=new ObservableCollection<Details>();
}
}
My Details Class is as follows
public class Details
{
public int id {get; set;}
public string LastName{get; set;}
--------
-------
}
Now I have to bind the _headertext(TextBlock in header Template) with the FirstName and _contenttext(TextBlock in Content Template) with LastName.
Please help me in doing this.I need your help.
Thanks
Rani
Why not use databinding in XAML directly? You should not need to do this in code.
<Style x:Key=itemStyle TargetType=AccordionItem>
<Setter Porperty=HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding FirstName}"/>
</DataTemplate>
</Setter>
</Style>
<Accordion Style"{StaticResource itemStyle}">
<Accordion.ContentTemplate>
<DataTemplate>
<StackPanel>
<CheckBox/>
<TextBlock Text="{Binding LastName}"/>
</DataTemplate>
<Accordion.ContentTemplate>
</Accordion>
First, the TargetType is pointed at AccordionItem and you are trying to use the style on the Accordion element itself. This will never work. In order to get this to work, you will need to create two styles, one for the Accordion itself and one for the AccordionItem that you reference within the style for the accordion.
<Style x:Key="itemStyle" TargetType="layoutToolkit:AccordionItem">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="accordionStyle" TargetType="layoutToolkit:Accordion">
<Setter Property="ItemContainerStyle" Value="{StaticResource itemStyle}" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Content}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Then you define your accordion control like such:
<layoutToolkit:Accordion Height="Auto"
Name="accordion1"
ExpandDirection="Right"
SelectionMode="One"
ItemsSource="{Binding}"
Style="{StaticResource accordionStyle}">
</layoutToolkit:Accordion>

How can I use a custom TabItem control when databinding a TabControl in WPF?

I have a custom control that is derived from TabItem, and I want to databind that custom TabItem to a stock TabControl. I would rather avoid creating a new TabControl just for this rare case.
This is what I have and I'm not having any luck getting the correct control to be loaded. In this case I want to use my ClosableTabItem control instead of the stock TabItem control.
<TabControl x:Name="tabCases" IsSynchronizedWithCurrentItem="True"
Controls:ClosableTabItem.TabClose="TabClosed" >
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type Controls:ClosableTabItem}" >
<TextBlock Text="{Binding Path=Id}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type Entities:Case}">
<CallLog:CaseReadOnlyDisplay DataContext="{Binding}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
EDIT: This is what I ended up with, rather than trying to bind a custom control.
The "CloseCommand" im getting from a previous question.
<Style TargetType="{x:Type TabItem}" BasedOn="{StaticResource {x:Type TabItem}}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border
Name="Border"
Background="LightGray"
BorderBrush="Black"
BorderThickness="1"
CornerRadius="25,0,0,0"
SnapsToDevicePixels="True">
<StackPanel Orientation="Horizontal">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="20,1,5,1"/>
<Button
Command="{Binding Path=CloseCommand}"
Cursor="Hand"
DockPanel.Dock="Right"
Focusable="False"
Margin="1,1,5,1"
Background="Transparent"
BorderThickness="0">
<Image Source="/Russound.Windows;component/Resources/Delete.png" Height="10" />
</Button>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
<Setter TargetName="Border" Property="Background" Value="LightBlue" />
<Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
<Setter TargetName="Border" Property="BorderBrush" Value="DarkBlue" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
found a way,
derive a class from TabControl and override this function, in my case I want the items of the tab control (when bound) to be CloseableTabItems
public class CloseableTabControl : TabControl
{
protected override DependencyObject GetContainerForItemOverride()
{
return new CloseableTabItem();
}
}
HTH Someone
Sam
You don't want to set the DataType of the DataTemplate in this case. The value of the ItemTemplate property is used whenever a new item needs to be added, and in the case of a tab control it will be used to create a new TabItem. You should declare an instance of your class within the DataTemplate itself:
<TabControl x:Name="tabCases" IsSynchronizedWithCurrentItem="True" Controls:ClosableTabItem.TabClose="TabClosed">
<TabControl.ItemTemplate>
<DataTemplate>
<Controls:ClosableTabItem>
<TextBlock Text="{Binding Path=Id}" />
</Controls:ClosableTabItem>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type Entities:Case}">
<CallLog:CaseReadOnlyDisplay DataContext="{Binding}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
This will cause a new ClosableTabItem to be created whenever a new tab is added to the TabControl.
Update; From your comment, it sounds like that the ItemTemplate controls what is created within the TabItem, rather than changing the TabItem itself. To do what you want to do, but for a TreeView, you would set the HeaderTemplate. Unfortunately, I don't see a HeaderTemplate property of TabControl.
I did some searching, and this tutorial modifies the contents of the tab headers by adding controls to TabItem.Header. Maybe you could create a Style for your TabItems that would add the close button that your class is currently adding?

Resources