How to select first item in expanded group (listview) - c#

Can anyone help me with this problem (c# wpf):
I have a ListView with this Style for my Expander (for each group):
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="False">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
When the user expands the Expander, I would like to select the first item in the expanded group.
I added my group like this (CustomerOrderList = ListView):
CustomerOrderList.ItemsSource = OrderDetails.DefaultView;
CollectionView cv = (CollectionView)CollectionViewSource.GetDefaultView(CustomerOrderList.ItemsSource);
PropertyGroupDescription pgd = new PropertyGroupDescription("OrderInfo");
cv.GroupDescriptions.Add(pgd);
Is this possible?
Thanks,
Senne

Yes it is possible.
Include Linq namespace
using System.Linq;
Handle the Expander's Expanded event
<Expander Expanded="GroupExpander_Expanded" IsExpanded="False" ... />
Code Behind ...
private void GroupExpander_Expanded(object sender, RoutedEventArgs e)
{
var expander = sender as Expander;
//Extract the group
var groupItem = expander.DataContext as CollectionViewGroup;
//Set the first item from the group to ListBox's Selected Item property.
CustomerOrderList.SelectedItem = groupItem.Items.First();
}
If you are using MVVM then use the Attached Property behavior to wrap this functionality into it.
Hope this helps,

Related

C# UWP Template10.Validation Change Style

With "Template10.Validation", I want to change style.
First I made this Style for "validate:ControlWrapper".
<Style TargetType="validate:ControlWrapper">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="validate:ControlWrapper">
<StackPanel>
<ContentPresenter Content="{TemplateBinding Content}" />
<ItemsControl ItemsSource="{Binding Errors, Source={TemplateBinding Properties[PropertyName]}}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Foreground="Red" Text="{Binding}" Visibility="{Binding IsValid}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and Here is the result.
Something is strange. because I want to display Validation warning message for ONLY first name. but It display every warning. from address, from postal code.
My main quesiton
How to access "ValidatableModelBase.Property["PropertyName"].Errors" in Xaml.
because [] branket is not possible to use in XAML binding. How to accesss ??
with lot of my time, I finally find a solution for my own question...
First is my model class.
public class SettingEmail
: Template10.Validation.ValidatableModelBase
{public string EmailReceivers { get { return Read<string>(); } set { Write(value); } }}
Next is Property to bind. ( in my ViewModel class )
public SettingEmail SettingEmailModel{ get { return se; } set { this.Set(ref se, value); } }
Next is XAML code.
<validate:ControlWrapper DataContext="{Binding SettingEmailModel}"
PropertyName="EmailReceivers"
Style="{StaticResource validationNotify}">
<TextBox Text="{Binding EmailReceivers, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
MinHeight="400" Style="{StaticResource SettingStyle_MultilineTextBox}"/>
</validate:ControlWrapper>
and Last is Style in Resource file.
<Style x:Key="validationNotify" TargetType="validate:ControlWrapper">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="validate:ControlWrapper">
<StackPanel >
<ContentPresenter Content="{TemplateBinding Content}"/>
<ItemsControl DataContext="{TemplateBinding Property}"
ItemsSource="{Binding Errors, Source={TemplateBinding Property}}"
Style="{StaticResource validationNotifyMessage}"
>
<ItemsControl.ItemTemplate >
<DataTemplate>
<StackPanel>
<TextBlock Foreground="Red" Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I hope it help someone.
and I am sorry with my poor question's descriptions...I will try improve next...

How to add a GridView from PageResource to a pivotItem dynamically in UWP?

I'm trying to create mutiple PivotItems dynamically in the c# end and then for every PivotItem I want the set the content as a GridView which has a Datatemplate where elements are bound dynamically.
XAML code:
<Page.Resources>
<GridView x:Key="pivoteItemGV"
Margin="18,10,0,0"
Background="#191919"
SelectionMode="None">
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
</Style>
</GridView.ItemContainerStyle>
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel MaxWidth="300">
<TextBlock x:Name="ItemNameTB" Text="{Binding ItemName}"/>
<TextBlock x:Name="ItemDescriptionTB" Text="{Binding ItemDescription}"
TextWrapping="WrapWholeWords"/>
<TextBlock x:Name="ItemPriceTB" Text="{Binding ItemPrice}" />
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Page.Resources>
And on the C# end
private void BindTheContentToPage()
{
foreach(var categoryItem in contentResourceDictionary)
{
PivotItem categoryPivotItem = new PivotItem();
categoryPivotItem.Header = categoryItem.Key;
GridView gv = this.Resources["pivoteItemGV"] as GridView;
categoryPivotItem.Content = gv;
categoryPivotItem.DataContext = categoryItem.Value;
mainContentPivot.Items.Add(categoryPivotItem);
}
}
The app crashes at categoryPivotItem.Content = gv; stating Value does not fall within the expected range.
Is what I'm doing right does? As I'm not sure whether multiple copies of Page.Resource contents, GridView in this case is duplicated.
Thanks for the help in advance.
Don't put visual elements directly into the Resources section as you did. You can put DataTemplates there.
You need to set the PivotItem.ContentTemplate property to some DataTemplate. And set the PivotItem.Content property to your data object you want to bind to.
XAML code:
<Page.Resources>
<DataTemplate x:Key="pivoteItemGVTemplate">
<GridView
ItemsSource="{Binding}"
Margin="18,10,0,0"
Background="#191919"
SelectionMode="None">
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
</Style>
</GridView.ItemContainerStyle>
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel MaxWidth="300">
<TextBlock x:Name="ItemNameTB" Text="{Binding ItemName}"/>
<TextBlock x:Name="ItemDescriptionTB" Text="{Binding ItemDescription}"
TextWrapping="WrapWholeWords"/>
<TextBlock x:Name="ItemPriceTB" Text="{Binding ItemPrice}" />
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</DataTemplate>
</Page.Resources>
And in C# codebehind:
private void BindTheContentToPage()
{
foreach(var categoryItem in contentResourceDictionary)
{
PivotItem categoryPivotItem = new PivotItem();
categoryPivotItem.Header = categoryItem.Key;
var template = this.Resources["pivoteItemGVTemplate"] as DataTemplate;
categoryPivotItem.ContentTemplate = template;
categoryPivotItem.Content = categoryItem.Value;
mainContentPivot.Items.Add(categoryPivotItem);
}
}
If your categoryItem.Value is a List of data objects, then add an attribute to the GridView (as I did in the XAML):
ItemsSource="{Binding}"

How to display only a property of an item on the ListView

I have added a list of objects of the class "Employee" on a ListView, and i want it to display only the attribute "Name" on it, but when the item is selected, i want it to catch the object "Employee" to add to another List.
Here is my code. It displays the object Employee on the ListView. I want it to display the attribute Name.
private void PopulateEmployeeList()
{
List<Employee> staff = Presenter.GetEmployee();
foreach (Employee person in staff)
lstEmployee.Items.Add(person);
}
XAML
<Border Grid.Column="0" Grid.Row="1" HorizontalAlignment="Center" Width="230" >
<ListView Name="lstFuncionarios" />
</Border>
You can try in your xaml:
<ListView x:Name="lv" HorizontalAlignment="Left" Height="149" Margin="359,111,0,0" VerticalAlignment="Top" Width="138">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}"/>
</GridView>
</ListView.View>
</ListView>
You could define ItemContainerStyle for your ListView:
<ListView Name="lstFuncionarios">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<TextBlock Text="{Binding Name}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
This solution is good if you do not know the final face of ListViewItem, so you will be able to rewrite it when you want.
If you need just to display Name and nothing else - the solution of #S_Lord is good:
lstFuncionarios.DisplayMemberPath = "Name";
or
<ListView Name="lstFuncionarios" DisplayMemberPath="Name"/>
Hope, it helps

Access a control from within a DataTemplate with its identifying name

In my WPF application I have a ComboBox control that is located inside a Grid Control. In XAML I am assigning a name to the ComboBox:
<DataGridTemplateColumn Header="Status">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center" Text="{Binding name_ru}" Width="Auto" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Name="stcom" Style="{DynamicResource ComboBoxStyle}" SelectionChanged="status_SelectionChanged" Height="auto" Width="Auto">
<ComboBox.BorderBrush>
<SolidColorBrush Color="{DynamicResource Color1}"/>
</ComboBox.BorderBrush>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
With the method FindName(string) I am trying to refer to the ComboBox with its associated name:
ComboBox stcom
{
get
{
return (ComboBox)FindName("stcom");
}
}
if (stcom != null)
{
stcom.ItemsSource = list;
}
But obviously the control can not be found because the reference stcom remains null.
The question now is how to refer to my ComboBox using its name property ?
The answer is:
<Style x:Key="CheckBoxStyle1" TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<StackPanel Orientation="Horizontal">
<Grid>
<TextBlock Name="tbUserIcon" Text="t1" />
<TextBlock Name="tbCheck" Text="✓" />
</Grid>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and C#:
checkBox.ApplyTemplate();
var tbUserIcon= (TextBlock)checkBox.Template.FindName("tbUserIcon", checkBox);
don't forget the checkBox.ApplyTemplate() be fore Template.FindName() it's important!
First you have to get access to the control template which it has been applied to, then you can find an element of the template by name.
Have a look at the MSDN knowledge base :
How to: Find ControlTemplate-Generated Elements
You can't access controls that are part of a DataTemplate with their name.
You can try to read about some workarounds for example
WPF - Find a Control from DataTemplate in WPF
You can also have a look at the dozens of posts here on SO issuing this topic for example
here
here
here
here
here
here
here
here

Grouping in datagrid - rows not getting displayed

I have to group the data int the datagrid.
I have done following for that:
Have added the style to resources as:
> <Style x:Key="GroupHeaderStyle"
> TargetType="{x:Type GroupItem}">
> <Setter Property="Template">
> <Setter.Value>
> <ControlTemplate TargetType="{x:Type GroupItem}">
> <Expander IsExpanded="False"
> >
> <Expander.Header>
> <TextBlock Text="{Binding Name}"/>
> </Expander.Header>
> <ItemsPresenter />
> </Expander>
> </ControlTemplate>
> </Setter.Value>
> </Setter>
> </Style>
I have applied the style as:
<dg:DataGrid Grid.Row="1" Name="dgAuthor" HorizontalScrollBarVisibility="Hidden"
AutoGenerateColumns="False" RowHeaderWidth="17" RowHeight="25">
<dg:DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<dg:DataGridRowsPresenter/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</dg:DataGrid.GroupStyle>
</dg:DataGrid>
I have infoList as a ObservableCollection and have assigned it as itemssource as follows:
ListCollectionView lcv = new ListCollectionView(infoList);
lcv.GroupDescriptions.Add(new PropertyGroupDescription("Author"));
dgAuthor.ItemsSource = lcv;
where Info is class which has Author,Book,Year properties.
I have to group the datagrid on Author property.
I am able to display the explander but cannot see any rows in it.
Can anybody tell me whats wrong with the code?
Setting AutoGenerateColumns="True" explicitely solves the problem.
I also added the column definitions.

Categories