Data Binding with Silverlight accordion Control - silverlight

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>

Related

WPF Bound ListView Double Click event

I'm new to WPF so please forgive any of the below that doesn't make sense...
I've set up a view model, which is bound to a WPF List view data template. The source objects (belonging to a class called BrowserItem) are in an ObservableCollection, and I use a CollectionViewSource which diplays them in the ListView - after several headaches this works really well.
I thought the simplest part would be the handling when a user double clicks on something, but I was wrong.
The Event attached to the ListView returns the TextBlock control rather than the BrowserItem source object that was clicked on.
Can anyone point me to a simple way of obtaining the original item (BrowserItem) when the control is clicked on - I've seen several ways of doing this, but they all seem very complex to my simple mind.
A simple example would be great.
This is the XAML for the list view if its of use:
<ListView Name="ViewList"
ItemsSource="{Binding GroupItems}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Expander>
<Expander.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Children.Count}"
Value="0">
<Setter Property="Expander.Visibility"
Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<ListBox ItemsSource="{Binding Children}" />
</Expander>
<TextBlock Text="{Binding Name}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Active}"
Value="true">
<Setter Property="Background"
Value="YellowGreen" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander>
<Expander.Header>
<TextBlock Text="{Binding Name}" />
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
Thanks.
You can use EventSetter to add MouseDoubleClick event to listview like below:
<ListView ItemsSource="{Binding Source}" SelectedItem="{Binding SelectedModel, Mode=TwoWay}">
<!--<Behaviors:Interaction.Triggers>
<Behaviors:EventTrigger EventName="MouseDoubleClick">
<Behaviors:InvokeCommandAction Command="{Binding DataContext.Command, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" />
</Behaviors:EventTrigger>
</Behaviors:Interaction.Triggers>-->
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type local:Model}">
<TextBlock Text="{Binding Age}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In this way you just handle it in code behand , not in ViewModel.
If you want handle it in viewmodel, you need one class like this:
public class EventToCommand
{
public static string GetEventName(DependencyObject obj)
{
return (string)obj.GetValue(EventNameProperty);
}
public static void SetEventName(DependencyObject obj, string value)
{
obj.SetValue(EventNameProperty, value);
}
public static readonly DependencyProperty EventNameProperty =
DependencyProperty.RegisterAttached("EventName", typeof(string), typeof(EventToCommand), new PropertyMetadata("", OnEventNameChanged));
public static void OnEventNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public static ICommand GetCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(CommandProperty);
}
public static void SetCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(CommandProperty, value);
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(EventToCommand), new PropertyMetadata(OnCommandChanged));
public static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var element = d as FrameworkElement;
EventInfo eventInfo = d.GetType().GetEvent(GetEventName(d));
var eventHandlerMethodInfo = typeof(EventToCommand).GetMethod("Invoke", BindingFlags.Static | BindingFlags.Public);
eventInfo.AddEventHandler(d, Delegate.CreateDelegate(eventInfo.EventHandlerType, eventHandlerMethodInfo));
}
public static void Invoke(object sender,EventArgs e)
{
var command = GetCommand(sender as FrameworkElement);
command.Execute(e);
}
}
And use class EventToCommand like this:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="local:EventToCommand.EventName" Value="MouseDoubleClick" />
<Setter Property="local:EventToCommand.Command" Value="{Binding DataContext.Command, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" />
</Style>
</ListView.ItemContainerStyle>

WPF MVVM-Light adding an image to a listview item when selecting

I have a ListView that I want to be able to add a 'Delete' button to, with a command attached to it, when I select an item. I can't find anything about this on stack which is quite surprising.
One way you could do this is by applying a style to the ListViewItem in the ListView.Resources. In the Style, you set the ContentTemplate to a DataTemplate with only a TextBlock. Then you give the Style a Trigger that is tied to the IsSelected property. In the Trigger you'll set the ContentTemplate to a new DataTemplate with a TextBlock and a Button. The Command property of the Button is bound to the ViewModel using the RelativeSource binding and the CommandParameter is bound to the item so that it gets passed along as a parameter to your DeleteCommand.
XAML
<ListView Margin="3"
MinWidth="200"
ItemsSource="{Binding Items}">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding SomeProperty}"
Margin="3" />
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding SomeProperty}"
Margin="3" />
<Button Content="Delete"
Margin="3"
Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}}"
CommandParameter="{Binding }" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ListView.Resources>
</ListView>
ViewModel
private ICommand _DeleteCommand;
public ICommand DeleteCommand
{
get
{
if (_DeleteCommand == null)
{
_DeleteCommand = new RelayCommand<ExampleModel>(param => DeleteItem(param));
}
return _DeleteCommand;
}
}
private void DeleteItem(ExampleModel item)
{
MessageBox.Show(item.SomeProperty);
}
I just have the Delete method showing the value in a MessageBox for demo purposes. You should be able to modify the DataTemplate and Delete method to meet your needs.

Expander inside ListViewItem

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.

How to conditionally insert a Checkbox in a list item of a customized ListView?

I try to make a customized ListView which fills each list item with some stuff and an initial Checkbox if desired. Currently no Checkbox is displayed so I guess my code of the ContentControl stuff is somehow erroneous.
<ListView xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<!-- Each list item: [Checkbox] Label -->
<StackPanel Orientation="Horizontal">
<!-- The code for the optional check box -->
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding IsCheckable}" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<CheckBox IsChecked="{Binding Path=SomeProperty}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
<!-- The non-optional test label -->
<Label Content="Test Content" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</ListView.View>
</ListView>
The Code behind:
public partial class MyListView : ListView {
public MyListView () {
InitializeComponent();
}
public bool IsCheckable
{
get { return (bool)GetValue(IsCheckableProperty); }
set { SetValue(IsCheckableProperty, value); }
}
public static readonly DependencyProperty IsCheckableProperty =
DependencyProperty.Register(
"IsCheckable",
typeof(bool),
typeof(AppropriatenessWidget),
new UIPropertyMetadata(false));
}
{Binding IsCheckable} binds to the DataContext not the control, use for example:
{Binding IsCheckable,
RelativeSource={RelativeSource AncestorType=local:MyListView}}
Also i doubt that this subclassing approach is such a good idea, this could easily be handled via an underlying DataContext.

ListBox with embedded CheckBox restricting one item to be checked

I have a ListBox containing an ItemTemplate made up of a StackPanel containing a CheckBox and a Label. I want to allow only one list item to be checked at a time. I am having trouble understanding how I can get this accomplished. Here is the XAML describing the listbox:
<ListBox Grid.Row="0"
Grid.Column="0"
Width="180"
HorizontalAlignment="Left"
x:Name="listboxPlayers"
ItemsSource="{Binding Players}"
SelectedItem="{Binding SelectedPlayer, Mode=TwoWay}"
ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsDefault, Mode=TwoWay}"
VerticalAlignment="Center"
Checked="CheckBox_Checked"
Unchecked="CheckBox_Unchecked"/>
<Label Content="{Binding Name}"
VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
A Player is defined as this:
public class Player
{
public string Name { get; set; }
public bool IsDefault { get; set; }
}
My list of Players is defined like this:
public ObservableCollection<Player> Players { get; private set; }
My SelectedPlayer is defined like this:
public static readonly DependencyProperty SelectedPlayerProperty =
DependencyProperty.Register("SelectedPlayer", typeof(Player), typeof(MainWindow),
new FrameworkPropertyMetadata());
public Player SelectedPlayer
{
get { return (Player)GetValue(SelectedPlayerProperty); }
set { SetValue(SelectedPlayerProperty, value); }
}
I haven't been able to find a post or question that can help me. I've played with using a Checked event handler for the CheckBox but I can't seem to wrap my head around how I can relate the list to the correct Player in the list because the ListBox doesn't adjust the SelectedPlayer when the CheckBox is checked or unchecked.
Thanks very much.
I usually use the following style for displaying a ListBox using CheckBoxes (You can use RadioButtons too by just replacing the CheckBox control with a RadioButton
<Style x:Key="CheckBoxListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="KeyboardNavigation.DirectionalNavigation" Value="Cycle" />
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}" >
<Setter Property="Margin" Value="2, 2, 2, 0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Background="Transparent">
<CheckBox IsHitTestVisible="False" Focusable="false"
Content="{TemplateBinding ContentPresenter.Content}"
IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
Then it is simply used by something like
<ListBox ItemsSource="{Binding Players}"
Style="{StaticResource CheckBoxListBoxStyle}"
SelectedItem="{Binding SelectedPlayer, Mode=TwoWay}">
If you have something that should behave like a RadioButton, why not use a RadioButton?
Try configuring your ListBox to Selection Mode Single. And rather than a separate label you could just bind Name to the Content property of the CheckBox. I like the way that spaces. And you may need to implement InotifyPropertyChanged on player.

Resources