Item controls in wpf mvvm - wpf

I am working on wpf and using an ItemsControl to represent a list of class on the UI.
My code is like this:
<ItemsControl ItemsSource="{Binding Path=UsecaseListItems}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel>
<CheckBox IsChecked="{Binding Path=IsSelected,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay,IsAsync=True}"
Margin="2,5"/>
<Button Content="{Binding UsecaseName}"
Margin="2,5"/>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Now I wand to add a header to both the columns (Select all and UseName) at the top of the list. How can I do it??

Below is the solution (Not a good one but I supposed worse design are also possible) and please change bindings in your code:
XAML:
<ItemsControl ItemsSource="{Binding Path=list}" >
<ItemsControl.Template>
<ControlTemplate>
<StackPanel Orientation="Vertical">
<Border BorderThickness="5" BorderBrush="DarkGray">
<StackPanel Orientation="Horizontal">
<Button Content="Select All" Width="80" HorizontalAlignment="Stretch"/>
<Button Content="User name" Width="80" HorizontalAlignment="Stretch"/>
</StackPanel>
</Border>
<Border BorderThickness="5" BorderBrush="LightGray">
<ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=ItemsSource}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel>
<CheckBox IsChecked="{Binding Path=DeviceState,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay,IsAsync=True}"
HorizontalAlignment="Stretch" Width="100" Margin="2,5"/>
<Button Content="{Binding Name}" HorizontalAlignment="Stretch" Width="100" Margin="2,5"/>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
</StackPanel>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
Output
Why do you want buttons as header? can't you just put buttons outside the ItemsControl?

It is preferable to go with ListView control instead of ItemsControl for what you need.
Here is the sample. .
<Grid>
<Grid.Resources>
<DataTemplate x:Key="checkboxHeaderTemplate">
<CheckBox Checked="CheckBox_Checked"> //add command for MVVM
</CheckBox>
</DataTemplate>
<DataTemplate x:Key="CheckBoxCell">
<CheckBox IsChecked="{Binding Path=IsSelected, Mode=TwoWay}" >
</CheckBox>
</DataTemplate>
<DataTemplate x:Key="ButtonCell">
<Button Content="{Binding Path=UsecaseName, Mode=TwoWay}" >
</Button>
</DataTemplate>
</Grid.Resources>
<ListView ItemsSource="{Binding Path=UsecaseListItems}" >
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn HeaderTemplate="{StaticResource checkboxHeaderTemplate}"
CellTemplate="{StaticResource CheckBoxCell}" Width="auto">
</GridViewColumn>
<GridViewColumn HeaderTemplate="{StaticResource checkboxHeaderTemplate}"
CellTemplate="{StaticResource ButtonCell}" Width="auto">
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
</Grid>
Hope that helps.

Related

How to get value of textblock in mvvm

I have an ItemControl containing a list of elements.
I need to get the value of the TextBlock using MVVM.
This is my XAML code:
<ItemsControl ItemsSource="{Binding IhmtEcosystemFilterList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="5" Height="80" Background="LightBlue" BorderBrush="Black" Command="{Binding CmdStatistiqueEcoSystem, ElementName={Binding Name}}">
<StackPanel Width="150">
<TextBlock Text="{Binding Name}" Foreground="White" FontSize="17" Name="valueTxtBloc" />
<Image x:Name="imgAvion" Source="/Resources/Images/avion.png" Width="35"></Image>
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>

DataContext of parent

I am a newbie WPF. I need to acheive the following: I have a ModelView which contains Observable collection of class "Edata". Edata also contains another ObservableColelction of Class"eParams" which contains 4 properties.
now I have listbox which contains the list of Edata, and another listview which contains the params .
Every thing works fine. the challenge is the tool tip. I have in the Edata Class Property called AsStringToolTip. I use this property to give some hint to user and briefed info about the row where the mouse is over.
<ListBox x:Name="lbx1" Grid.Column="0" Grid.Row="1" ItemsSource="{Binding EData}" VerticalAlignment="Center" HorizontalAlignment="Center">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel VirtualizingPanel.VirtualizationMode="Recycling"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource Description}" TextWrapping="Wrap">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} , {1}">
<Binding Path="Edata.category" />
<Binding Path="Edata.EId" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- No Compar ListView -->
<ListView Grid.Column="1" Grid.Row="1" ItemsSource="{Binding SelectedItem.Edata.eparams ,ElementName=lbx1}" Grid.IsSharedSizeScope="True" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel VirtualizingPanel.VirtualizationMode="Recycling"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.View>
<GridView >
<GridViewColumn Header="Name" >
<GridViewColumn.CellTemplate>
<DataTemplate >
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Name}">
<TextBlock.ToolTip>
**<TextBlock DataContext="{Binding SelectedValue,ElementName=lbx1}" Text="{Binding Path=AsStringToolTip}">**
</TextBlock>
</TextBlock.ToolTip>
</TextBlock>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="ValueString" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding ValueString}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="value" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding value}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="paramtype">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding paramtype}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I hope I am clear enough. any Advise. Currently the tool tip shows nothing!!!
Since the Tooltip resides in its own visual tree it cannot find the ListBox when the binding is evaluated.
But you could bind the Tag property of the TextBlock to the ListBox and then bind the element in the Tooltip to the PlacementTarget of the ToolTip itself. It's probably better explained with some sample markup:
<GridViewColumn Header="Name" >
<GridViewColumn.CellTemplate>
<DataTemplate >
<StackPanel Orientation="Horizontal" >
<TextBlock Text="Name" Tag="{Binding ElementName=lbx1}">
<TextBlock.ToolTip>
<ToolTip>
<TextBlock Text="{Binding PlacementTarget.Tag.SelectedItem.AsStringToolTip,
RelativeSource={RelativeSource AncestorType=ToolTip}}" />
</ToolTip>
</TextBlock.ToolTip>
</TextBlock>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
The PlacementTarget in the binding path refers to the "Name" TextBlock.
The Tag property of this TextBlock returns a reference to the "lbx1" ListBox.
You can then get the AsStringToolTip property of the currently selected Edata object.

wpf ListBox looks like datagrid?

I have a listbox control in my app.
I want to change his style to being look like to Datagrid (borders, columns, row...).
I don't want to using stantard datagrid - because its control cannot binding itemtemplte.
I trying to do it:
<ListBox
ItemsSource="{Binding Items}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Name="listBox1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Border BorderThickness="1" BorderBrush="Black">
<TextBlock Text="{Binding Id}" Margin="5"/>
</Border>
<Border BorderThickness="1" BorderBrush="Black">
<TextBlock Text="{Binding Name}" Margin="5"/>
</Border>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But it not looking good - as following:
it what i want to achieve:
Using Grid.IsSharedSizeScope
result
i believe you want the columns to be re-sized based on your string length, so Grid.IsSharedSizeScope is your choice here
example xaml
<ListBox ItemsSource="{Binding Items}"
Grid.IsSharedSizeScope="True">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="name" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border BorderThickness="1"
BorderBrush="Black">
<TextBlock Text="{Binding Name}"
Margin="5" />
</Border>
<Border BorderThickness="1"
Grid.Column="1"
BorderBrush="Black">
<TextBlock Text="{Binding Id}"
Margin="5" />
</Border>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
if you move SharedSizeGroup to id like below
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition SharedSizeGroup="id" />
</Grid.ColumnDefinitions>
result
Using ListView with GridView
You have an option to use list view with grid view which will have same appearance as grid with flexibility of list
eg
<ListView ItemsSource="{Binding SourceItems}">
<ListView.View>
<GridView>
<GridViewColumn Header="Column1"
DisplayMemberBinding="{Binding Column1}" />
<GridViewColumn Header="Column2"
DisplayMemberBinding="{Binding Column2}" />
</GridView>
</ListView.View>
</ListView>
GridViewColumn offers you to modify CellTemplate, HeaderTemplate, HeaderContainerStyle, HeaderStringFormat etc.
I am sure you can achieve this using a grid control (It supports binding and everything else)
To fix your problem, you will have to give fixed widths to both your borders inside your stackpanel then your listbox items will look like a grid control.
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Border Width="150" BorderThickness="1" BorderBrush="Black">
<TextBlock Text="{Binding Id}" Margin="5"/>
</Border>
<Border Width="50" BorderThickness="1" BorderBrush="Black">
<TextBlock Text="{Binding Name}" Margin="5"/>
</Border>
</StackPanel>
Please let us know what problem you are having with GridControl and maybe we can fix that as well
Edit. If you were using a DataGrid your template would look like
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" HeadersVisibility="None">
<DataGrid.Columns>
<DataGridTemplateColumn Header="" Width="SizeToCells" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text={Binding Id}/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="" Width="SizeToCells" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text={Binding Name}/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Please note that I have set HeaderVisibility to false so that it doesnt look like a datagrid but instead looks like a list

sort a GridView when a column header is clicked

this is my wpf file i want sort a GridView when a column header is clicked
i try this make <GridView AllowsColumnReorder="true"> but not working
sorry for my bad English
<ListView Name="deviceListBox"
Width="630"
Height="282"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ItemsSource="{Binding Items}"
SelectionChanged="deviceListBox_SelectionChanged"
SelectionMode="Single">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn>
<GridViewColumn.HeaderTemplate>
<DataTemplate>
<Label Width="15"
Height="25"
Margin="10,0,0,0"
HorizontalAlignment="center"
VerticalAlignment="Center" />
</DataTemplate>
</GridViewColumn.HeaderTemplate>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<controls:PresenceIndicator Width="35"
Height="30"
Margin="7,0,0,0"
HorizontalAlignment="center"
VerticalAlignment="Center"
PhotoDisplayMode="Large"
SingleClickAction="ShowContactDetails"
Source="{Binding Path=SipURI}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.HeaderTemplate>
<DataTemplate>
<Label Width="95"
Height="25"
Margin="10,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="Username"
Foreground="Black" />
</DataTemplate>
</GridViewColumn.HeaderTemplate>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<Label Height="30"
Margin="7,0,0,0"
HorizontalAlignment="left"
VerticalAlignment="Center"
Content="{Binding Path=Username}"
Foreground="Black" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
I think ListView doest not support sorting by default. Yo need to create attached dependency property to handle the sorting.
refer - Automatically sort a GridView when a column header is clicked

Binding for nested ListView not working

I have a nested ListView, but the ItemSource binding is never firing. Am I missing something in here? Here you can see my parent list view, which is binding just fine. But the nested one does not.
<ListView ItemsSource="{Binding Items}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0">
<CheckBox IsChecked="True" Margin="0,0,5,0"></CheckBox>
<TextBlock Text="{Binding Name}" Margin="0,0,15,0"/>
<TextBlock Text="Task Set Loop: "/>
<TextBox Text="{Binding Scenarios}"/>
</StackPanel>
<ListView Grid.Row="1" ItemsSource="{Binding ChildItems, Converter={StaticResource DebugBindingConverter}}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Grid.Row="0">
<CheckBox IsChecked="True" Margin="0,0,5,0"></CheckBox>
<TextBlock Text="{Binding Name}" Margin="0,0,15,0"/>
<ComboBox SelectedItem="{Binding DependentTaskName}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
My binding for the ChildItems was at the wrong level. Changed that line to:
<ListView Grid.Row="1" ItemsSource="{Binding Path=DataContext.ChildItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
For UWP we can get it like this
<GridView x:Name="abc" ItemsSource="{Binding Path=DataContext.Companies,RelativeSource={RelativeSource Mode=TemplatedParent}}"></GridView>

Resources