Bind nested Command in Control Template - c#

I have following control template:
public sealed partial class ItemSelectorControl : Control
{
...
public ICommand SelectionCommand
{
get { return (ICommand)GetValue(SelectionCommandProperty); }
set { SetValue(SelectionCommandProperty, value); }
}
public static readonly DependencyProperty SelectionCommandProperty =
DependencyProperty.Register("SelectionCommand", typeof(ICommand), typeof(ItemSelectorControl), new PropertyMetadata(null));
public ItemSelectorControl()
{
DefaultStyleKey = typeof(ItemSelectorControl);
}
...
}
and the corresponding theme style:
<Style TargetType="controls:ItemSelectorControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:ItemSelectorControl">
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock
Style="{StaticResource SectionHeader}"
Text="{TemplateBinding Headline}"
Visibility="{TemplateBinding HeadlineVisibility}"/>
<ItemsControl
x:Name="CurrencyItemPanel"
ItemsSource="{TemplateBinding ItemCollection}"
MaxHeight="{TemplateBinding MaximumItemsControlHeight}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Style="{StaticResource ItemSelectorButtonStyle}"
Command="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=SelectionCommand}"
CommandParameter="{Binding Path=Code}">
<interactivity:Interaction.Behaviors>
<behaviour:ItemSelectorVisualStateBehaviour
StateChangeTrigger="{Binding Selected, Mode=TwoWay}"/>
</interactivity:Interaction.Behaviors>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How do I have to write the command binding?
Command="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=SelectionCommand}"
In WPF I would work with FindAncestor but since that is not available in WinRT I don't not how to bind? I can't use DataContext.SelectionCommand because the current DataContext is the ViewModel.

Related

ListView/DataGridView grouping's expand when item selected

I finish a ListView grouping and add a expander control.
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="{Binding Mode=TwoWay, Path=IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem, Mode=FindAncestor}}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" FontWeight="Bold" Foreground="Gray" FontSize="16" 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>
<ItemsPresenter/>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
The IsExpanded like
<Expander IsExpanded="{Binding Mode=TwoWay, Path=IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem, Mode=FindAncestor}}">
and I set lv.SelectedIndex to change selection, but it don't work!
I have no idea.
Xaml Design:
<Window.Resources>
<Style x:Key="groupheaderstyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Background="White" Foreground="Black">
<Expander.Header>
<TextBlock Text="{Binding Gropname}" />
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<DataGrid x:Name="dgdata" HorizontalAlignment="Left" Height="269" VerticalAlignment="Top" Width="292">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource groupheaderstyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
Xaml Design.cs
public class group
{
public string groupname { get; set; }
public string CLgroup { get; set; }
public string displayname { get; set; }
}
public Window4()
{
InitializeComponent();
ObservableCollection<group> samdata = new ObservableCollection<group>
{
new group{groupname="Group1",CLgroup="xxx",displayname="demo1"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
};
ListCollectionView collection = new ListCollectionView(samdata);
collection.GroupDescriptions.Add(new PropertyGroupDescription("groupname"));
dgdata.ItemsSource = collection;
}

Grouping data on Datagrid wpf

I want to regroup my data with an expander that contains the group name and contains all ClassMate name inside.
This is my class Group :
public class Group{
public List<ClassMate> CLGroup { get; set; }
public string GroupName { get; set; }}
My classMate class :
public class ClassMate: INotifyPropertyChanged{
public string Name { get; set; }
public string DisplayName { get; set; }}
I tried to do this with this Xaml but I don't know why it's not working
<DataGrid x:Name="gridMates" ItemsSource="{Binding Groups }" >
<DataGrid.GroupStyle>
<!-- Style for groups at top level. -->
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" >
<Expander.Header>
<DockPanel>
<TextBlock Text="{Binding Path=GroupName}" />
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsControl ItemsSource="{Binding Path=CLGroup}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=DisplayName}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
What am I doing wrong?
Thanks
You need to bind the ItemsSource property to a grouped source collection. The easiest way to do this is to use a CollectionViewSource:
<Grid>
<Grid.Resources>
<CollectionViewSource x:Key="groups" Source="{Binding Groups}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="GroupName" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Grid.Resources>
<DataGrid x:Name="gridMates" ItemsSource="{Binding Source={StaticResource groups}}" AutoGenerateColumns="False">
<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>
<DockPanel>
<TextBlock Text="{Binding Path=Name}" />
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsControl ItemsSource="{Binding Path=Items[0].CLGroup}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=DisplayName}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
</Grid>
XAML Design
<Window.Resources>
<Style x:Key="groupheaderstyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Background="White" Foreground="Black">
<Expander.Header>
<TextBlock Text="{Binding Gropname}" />
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<DataGrid x:Name="dgdata" HorizontalAlignment="Left" Height="269" VerticalAlignment="Top" Width="292">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource groupheaderstyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
XAML Design.CS
public class group
{
public string groupname { get; set; }
public string CLgroup { get; set; }
public string displayname { get; set; }
}
public Window4()
{
InitializeComponent();
ObservableCollection<group> samdata = new ObservableCollection<group>
{
new group{groupname="Group1",CLgroup="xxx",displayname="demo1"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group2",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group2",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group2",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group3",CLgroup="zzz",displayname="demo3"},
new group{groupname="Group3",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group3",CLgroup="yyy",displayname="demo2"},
};
ListCollectionView collection = new ListCollectionView(samdata);
collection.GroupDescriptions.Add(new PropertyGroupDescription("groupname"));
dgdata.ItemsSource = collection;
}

Access the Window's DataContext from a DataTemplate in a DataGrid

I use a DataGrid in my WPF application. It does feature RowDetails for selected Rows. Therefor I set the RowDetailsTemplate. Inside this DataTemplate i want to access my Window's DataContext. For Example I have a lable inside my RowDetailsTemplate and I want to bind it's content-property to a property of my viewModel which is in the DataContext of the window. How do I achieve this.
Thank you for your help!
Look at this usage of RelativeSource based binding, like {Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}. Here is example:
Xaml:
<DataGrid ItemsSource="{Binding Strings}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="String" Width="SizeToCells" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type soDataGridHeplAttempt:ClicableItemsModel}">
<ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding ClickableItems}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Button Width="70" Content="{Binding }" Style="{StaticResource ButtonInCellStyle}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.Command}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Content}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
View model:
private ICommand _command;
public ObservableCollection<ClicableItemsModel> Strings { get; set; }
public ICommand Command
{
get { return _command ?? (_command = new RelayCommand<object>(MethodOnCommmand)); }
}
private void MethodOnCommmand(object obj)
{
}
Model pu this inside the the model class:
public ObservableCollection<String> ClickableItems { get; set; }
regards,

How to display a clickable list of things to datagrid cell?

I have a datagrid, in one of the columns I want to display a string - in each cell in the column a different string(that I get from the user) that looks like this: "data1, data2, data3, ..." and make each datai(data1,data2,...) clickable.
how can I achieve that?
Here is edited version:
Xaml (put it inside the <DataGridTemplateColumn.CellTemplate):
<DataTemplate DataType="{x:Type soDataGridHeplAttempt:ClicableItemsModel}">
<ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding ClickableItems}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Button Width="70" Content="{Binding }" Style="{StaticResource ButtonInCellStyle}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.Command}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Content}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</DataTemplate>
Xaml resources use this if you want to edit the button content:
<Style x:Key="ButtonInCellStyle" TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Background="{x:Null}" MaxWidth="40" BorderBrush="{x:Null}" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Button}}, Path=Content, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
HorizontalAlignment="Center" VerticalAlignment="Center" ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Text}">
</TextBox>
</DataTemplate>
</Setter.Value>
</Setter>
Viewmodel:
private ICommand _command;
public ObservableCollection<ClicableItemsModel> Strings { get; set; }
public ICommand Command
{
get { return _command ?? (_command = new RelayCommand<object>(MethodOnCommmand)); }
}
private void MethodOnCommmand(object obj)
{
}
Clickable Items model code (create the ClicableItemsModel class an put it there):
public ObservableCollection<String> ClickableItems { get; set; }
when running:
regards,

Bind element to a child object XAML

first the code :
MyStyle.xaml
<Style x:Key="MyStyle" TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<TextBlock x:Name="MyTextGen" Text="Foo"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
MyUserControl.xaml
<UserControl x:Name="Mycontrol">
<Grid>
<Button x:Name="Btn1" Style="{StaticResource MyStyle}"/>
<Button x:Name="Btn2" Style="{StaticResource MyStyle}"/>
</Grid>
</UserControl>
MyPage.xaml
<common:MainPage x:Name="MainPage">
<Grid>
<Popup x:Name="CatTool" IsOpen="False" HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="0 0 300 500">
<cat:MyControl >
<cat:MyContro.Transitions>
<TransitionCollection>
<PopupThemeTransition/>
</TransitionCollection>
</cat:MyContro.Transitions>
</cat:CatPagecontrol>
</Popup>
</Grid>
</common:MainPage>
Info.cs
MyDict = new Dictionary<string, string>
{
{"First", "MyFirst"},
{"Second", "MySecond")}
};
I would like to bind MyDict "First" and "Second" in MyTextGenby the MainPage, is it possible ?
MyStyle.xaml
<Style x:Key="MyStyle" TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<TextBlock x:Name="MyTextGen" Text="{TemplateBinding Content}"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
MyUserControl.xaml
<UserControl>
<Grid>
<ItemsControl ItemsSource="{Binding Path=Buttons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Style="{StaticResource MyStyle}" Content="{Binding}" Tag="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
MyUserControl.xaml.cs
public IEnumerable<string> Buttons {
get { return (IEnumerable<string>)GetValue(ButtonsProperty); }
set { SetValue(ButtonsProperty, value); }
}
public static readonly DependencyProperty ButtonsProperty =
DependencyProperty.Register("Buttons", typeof(IEnumerable<string>),
typeof(MyUserControl));
MainWindow.xaml
<Border>
<cat:MyUserControl Buttons="{Binding Buttons}" />
</Border>
MainWindow.xaml.cs
public IEnumerable<string> Buttons { get; set; }
private Dictionary<string, string> MyDict = new Dictionary<string, string> { { "First", "MyFirst" }, { "Second", "MySecond" } };
public MainWindow() {
this.DataContext = this;
Buttons = MyDict.Keys;
InitializeComponent();
}

Categories