Stretch GridViewItem to fill screen - c#

I'm making an app that is similar to windows8 calendar app and I have ran into a problem.
So how to stretch my groups in GridView to fill all available space (the same as in month view in windows app)? I've tried to set property HorizontalContentAlignment of GridViewItem but it doesn't take an effect.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<GridView Padding="116,37,40,46" ItemsSource="{Binding Source={StaticResource DayGroups}}">
<GridView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Day}" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</GridView.ItemContainerStyle>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Key}" Style="{StaticResource SubtitleTextBlockStyle}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
</Grid>
Thanks
ItemSource is just collection of
public class GroupViewModel<TKey, TItem> : ViewModelBase
{
private ObservableCollection<TItem> _items;
private TKey _key;
public TKey Key
{
get { return _key; }
set { Set(ref _key, value); }
}
public ObservableCollection<TItem> Items
{
get { return _items; }
set { Set(ref _items, value); }
}
}
where TKey is string, TItem is DateTime

Related

Proper MVVM for a WPF ListCollectionView?

I'm implementing a ListCollectionView so I can get groupings of objects within my datagrid. It seems to be working pretty well, but it doesn't feel like proper MVVM. I'm a little confused because a property can't directly be defined as a ListCollectionView. Instead, a separate collection has to be provided that implements IList.
The original ObservableCollection<EntityConcept> has too much information to display in the datagrid at once. The user selects one of the EntityConcept using a combobox, then a ListCollectionView<PropertyItem> is constructed to display all of the PropertyItem that belong to that EntityConcept.
I feel like it would make sense for the ObservableCollection<PropertyItem> to be defined as a ListCollectionView from the start. However, I don't think I can do that.
public class EntityConcept
{
private string _Name;
private ObservableCollection<PropertyItem> _propertyList;
public ObservableCollection<PropertyItem> propertyList
{
get
{
return _propertyList;
}
set
{
_propertyList = value;
}
}
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}
}
Instead, a ListCollectionView is constructed based on what the user selects in the combobox:
<ComboBox x:Name="ifcCombo"
Grid.Column="2"
Grid.Row="1"
Margin="0,3,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="150"
DisplayMemberPath="ifcEntity"
SelectedItem="{Binding chosenConcept}"
ItemsSource="{Binding ConceptList}"/>
<!--Grid.Row 3-->
<DataGrid x:Name="propertiesTable"
ItemsSource="{Binding chosenConceptProperties}"
Grid.Column="1"
Grid.ColumnSpan="3"
Grid.Row="3"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
AutoGenerateColumns="False"
CanUserAddRows="False"
Margin="0,25,0,0" CellEditEnding="propertiesTable_CellEditEnding">
<DataGrid.Columns>
<DataGridCheckBoxColumn Width="75" MinWidth="50" Header="" IsReadOnly="False" Binding="{Binding On}"/>
<DataGridTextColumn Width="10*" MinWidth="250" Header="Property Name" Binding="{Binding PropertyName}" IsReadOnly="True" FontSize="10" />
<DataGridTextColumn Width="10*" MinWidth="250" Header="Mapping" Binding="{Binding Mapping}" IsReadOnly="False" FontSize="10" />
<!--<DataGridTemplateColumn Width="*" Header="" CellTemplateSelector="{StaticResource myDynamicTemplateSelector}"/>-->
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="{Binding StringType, Converter={StaticResource stringToBrush}}"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Background="White" Foreground="Black" BorderThickness="1,1,1,5">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="HeaderCheckBox" Grid.Column="2" Tag="{Binding Name}" Margin="5,0,0,0" Click="CheckAll"/>
<TextBlock Grid.Column="0" Text="{Binding Path=Name}" Foreground="#2a5fa4" FontWeight="Bold" Margin="10,0,0,0"/>
</StackPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter/>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
Instead, the ListCollectionView is manually constructed every time the chosenConcept is set. This doesn't feel correct to me, and I think there must be a cleaner way.
private ObservableCollection<EntityConcept> _ConceptList = new ObservableCollection<EntityConcept>();
private EntityConcept _chosenConcept = new EntityConcept();
private ListCollectionView _chosenConceptProperties;
public EntityConcept chosenConcept
{
get
{
return _chosenConcept;
}
set
{
_chosenConcept = value;
OnPropertyChanged(nameof(chosenConcept));
ConstructChosenConcept();
}
}
public ListCollectionView chosenConceptProperties
{
get
{
return _chosenConceptProperties;
}
set
{
_chosenConceptProperties = value;
OnPropertyChanged(nameof(chosenConceptProperties));
}
}
public void ConstructChosenConcept()
{
if(chosenConcept != null)
{
chosenConceptProperties = new ListCollectionView(chosenConcept.propertyList);
chosenConceptProperties.GroupDescriptions.Add(new PropertyGroupDescription("Pset"));
name = chosenConcept.Name;
description = chosenConcept.Description;
objectType = chosenConcept.ObjectType;
tag = chosenConcept.Tag;
}
}

How to display a checked check box on the selected item of a ListView in uwp

I have a listview in uwp where i have to highlight the selected item by displaying the checked checkbox on the selected item. So please tell me how i achieved it.
My XAML code
<ListView x:Name="gvProcesses" SelectionChanged="GvProcesses_SelectionChanged" Grid.Row="1" Grid.ColumnSpan="2" Height="100" ItemsSource="{Binding ScanProcessNameCollection,Mode=OneWay}" SelectedItem="{Binding SelectedScanProcessName,Mode=TwoWay}" IsItemClickEnabled="True" SelectionMode="Single" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollMode="Enabled" ScrollViewer.IsHorizontalRailEnabled="True" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<!--<StackPanel Orientation="Horizontal" />-->
<ItemsStackPanel Orientation="Horizontal" Margin="0"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate >
<StackPanel Background="{ThemeResource SystemControlBackgroundAccentBrush}" >
<TextBlock Visibility="{Binding IsSelected,Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}"
x:Name="txtcheckbox" FontFamily="Segoe MDL2 Assets" Text="" FontSize="{ StaticResource SmallFontSize}" VerticalAlignment="Center" HorizontalAlignment="Left"></TextBlock>
<TextBlock Text="{Binding}" FontSize="{ StaticResource SmallFontSize}" VerticalAlignment="Center" TextWrapping="WrapWholeWords" Margin="0 40" HorizontalAlignment="Center"></TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="Margin" Value="2,0,2,0" />
<Setter Property="Padding" Value="0,0,0,0" />
<Setter Property="MinHeight" Value="50" />
<Setter Property="MaxHeight" Value="100" />
<Setter Property="MaxWidth" Value="80" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
checkboxes display on all items binding not work properly and It also not goes on converter when i debug it.
Selection Mode Multiple
If you need multiple selection with checkbox then you can change the property SelectionMode to Multiple and then set IsMultiSelectCheckBoxEnabled to True
Selection Mode Single
If you need single selection with checkbox you need to add checkbox to your grid and then bind it to a veriable. I have added a small example below
//Xaml Code
<ListView ItemsSource="{x:Bind line_items,Mode=OneWay}" SelectionChanged="ListView_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding is_checked,Mode=OneWay}"></CheckBox>
<TextBlock Text="{Binding value,Mode=OneWay}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
//C# Code
public sealed partial class MainPage : Page
{
public List<item> line_items = new List<item>();
public MainPage()
{
for (var i = 0; i < 10; i++)
line_items.Add(new item() { is_checked = false, value = "item" + i });
this.InitializeComponent();
}
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach(var item in line_items)
item.is_checked = false;
line_items[(sender as ListView).SelectedIndex].is_checked = true;
}
}
public class item : INotifyPropertyChanged
{
private bool? _is_checked;
private string _value;
public bool? is_checked
{
get { return _is_checked; }
set
{
_is_checked = value;
RaisePropertyChanged(nameof(is_checked));
}
}
public string value
{
get { return _value; }
set
{
_value = value;
RaisePropertyChanged(nameof(value));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}

Nested binding with templates

I am creating 'Lessons' tab in my application. The problem is in displaying data.
Timetable(List<DayInfo>) is binded to ItemsControl. Each DayInfo is an item in this ItemsControl. I tried to bind Exams collection to nested ItemsControl placed in ItemTemplate, but It's not working.
I'd like to know what I'm doing wrong. I guess my Exams binding is the problem.
Timetable:
private List<DayInfo> timetable;
public List<DayInfo> Timetable
{
get { return timetable; }
set
{
timetable = value;
NotifyOfPropertyChange(() => Timetable);
}
}
There is DayInfo.cs:
public class DayInfo : IValue
{
public string DayName { get; }
public List<ExamEntry> Exams { get; }
...
}
ExamEntry.cs:
public class ExamEntry : DayEntry, IValue
{
public string Description { get; }
...
}
XAML code:
<ItemsControl
ItemsSource="{Binding Timetable}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
...
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<StackPanel
Orientation="Horizontal"
Margin="0">
</StackPanel>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</ItemsControl.GroupStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label
Content="{Binding DayName}" /> <!-- It still works -->
<ItemsControl
ItemsSource="{Binding Exams}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label
Content="{Binding Description}" /> <!-- It's not displayed -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Everything is fine with this piece of code. I've forgotten about another part of project, where Timetable was bugged. Sorry for confusion.

Add a TextBox as the last element of an ItemsControl with WrapPanel

I am trying to implement the following scanarios
APPROACH SO FAR
Tried to implement it with an ItemsControl (with WrapPanel) and a TextBox wrapped inside a WrapPanel, but it does not have a desired output as there are two WrapPanels wrapping separately
<toolkit:WrapPanel Orientation="Horizontal">
<ItemsControl ItemsSource="{Binding someThing}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Border>
<TextBlock Text="somesomething" />
</Border>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<TextBox/>
</toolkit:WrapPanel>
I am thinking if I can add the TextBox at the END of the ItemsControl, but failed to do so. Please specify if there is any other workaround/ solution to any of my approaches
You need to use DataTemplateSelector for the ItemsControl and specify different templates for different list items.
public class BlockItem
{
// TODO
}
public class BoxItem
{
// TODO
}
public class MyTemplateSelector : DataTemplateSelector
{
public DataTemplate BlockTemplate { get; set; }
public DataTemplate BoxTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
if (item is BlockItem) return BlockTemplate;
else if (item is BoxItem) return BoxTemplate;
return base.SelectTemplateCore(item);
}
}
XAML:
<ItemsControl ItemsSource="{Binding someObject}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplateSelector>
<local:MyTemplateSelector>
<local:MyTemplateSelector.BlockTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="something"/>
</Grid>
</DataTemplate>
</local:MyTemplateSelector.BlockTemplate>
<local:MyTemplateSelector.BoxTemplate>
<DataTemplate>
<Grid>
<TextBox Text="something"/>
</Grid>
</DataTemplate>
</local:MyTemplateSelector.BoxTemplate>
</local:MyTemplateSelector>
</ItemsControl.ItemTemplateSelector>
</ItemsControl>
And you then add different types of objects to your items source:
someObject.Add(new BlockItem());
someObject.Add(new BlockItem());
someObject.Add(new BlockItem());
someObject.Add(new BlockItem());
someObject.Add(new BoxItem());
If you want the TextBox to be the last element, then you need it to be the last item in your ItemsSource list.

Bind nested Command in Control Template

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.

Categories