I tried to style my listview template, which contains a gridview. I tried to do it using an ItemsPresenter and it works fine but my gridview's header disappears.
What should i use to preserve my header?
<Style TargetType="{x:Type ListView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListView}">
<Border x:Name="Bd"
SnapsToDevicePixels="true">
<ScrollViewer Focusable="false">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Edit : My Listview
<ListView Name="findReplaceView" Margin="10" Grid.Row="1" Grid.Column="0"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
ItemsSource="{Binding FindAndReplaceItems}">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Find" DisplayMemberBinding="{Binding Find}"
Width="{Binding ElementName=helperField1, Path=ActualWidth}"/>
<GridViewColumn Header="Replace" DisplayMemberBinding="{Binding Replace}"
Width="{Binding ElementName=helperField2, Path=ActualWidth}"/>
</GridView>
</ListView.View>
</ListView>
It's because you didn't style the header part. This is how you should do it:
<Style TargetType="{x:Type ListView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- This is how your headers are presented -->
<ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=ListView},Path=View.Columns}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="LightGray" Background="MidnightBlue">
<TextBlock Foreground="WhiteSmoke"
TextAlignment="Center"
FontWeight="Bold"
Text="{Binding Header}"
Width="{Binding ActualWidth}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<!-- This is how your items are presented -->
<Border x:Name="Bd" Grid.Row="1"
SnapsToDevicePixels="true">
<ScrollViewer Focusable="false">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In the above code there are 2 Grid.RowDefinitions with height="Auto" and height="*" the first one is the area (i.e. the top row) that represents the header part and the second one is the remaining area that contains your ItemsPresenter and determines how your items are presented.
Edit
Since this is suppose to be a general style for a ListView that it's columns are already defined in some ListView.View, I thought using an ItemsControl for the headers part would make your style quite flexible. I modified my code sample accordingly in which the headers part is an ItemsControl with horizontal orientation that it's ItemsSource is bound to ListView.View.Columns. This way columns count in the style will depend on columns count in your ListView. Also the ItemsControl.ItemTemplate is a TextBlock that it's text is bound to the header of the respective column, therefore columns header in the style will be the same as columns headers in your ListView.
Related
I have a grid inside a CollectionView and I need to change the layout based on a certain condition, changing dynamically the size of the columns and rows and hiding/showing some specific columns.
The datasource of the collectionView is always the same.
Basically, I want to achieve something like this:
Default layout:
Alternative layout:
I saw that maybe I could use the DataTemplateSelectors, but is that the best way or is there another method?
You can use the Grid in the Collectionview and set the Grid format.
First, you can set the CollectionView ItemsLayout. Here is the example.
<CollectionView ItemsSource="{Binding Items}"
ItemsLayout="VerticalGrid, 3">
it will divide the CollectionView list into three vertical parts.
Second, you can make a Grid to preserve the data.
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="60" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
</Grid.ColumnDefinitions>
<Image Grid.Row="0"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Row="1"
Text="{Binding Location}" />
</Grid>
I have added a Style to the ResourceDictionary. The ControlTemplate contains a Grid with one Slider and two TextBlocks.
My problem is that i dont know how i can bind the textblock text. Is there any easy way to do it?
This is the code, how i would like to use the template in my view.xaml
<Slider Style="{StaticResource ComboSliderTheme}"
Minimum="0"
Maximum="100"
*Textbox myTitle ="Time"
*Textbox myValue ="23"/>
And this is the code i have added to the resource dictionary so far.
How do i have to modify the Textblock text= to get the wished result?
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type Slider}"
x:Key="ComboSliderTheme">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Slider">
<Grid VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Height="50"
Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock *Text="My Title" (Value to Bind)
Grid.Column="0"
Grid.Row="0"
/>
<TextBlock *Text="My Value" (Value to Bind)
Grid.Column="1"
Grid.Row="0"
/>
<Slider Grid.Row="1"
Grid.ColumnSpan="2"
Minimum="{TemplateBinding Property=Minimum}"
Maximum="{TemplateBinding Property=Maximum}"
/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</ResourceDictionary>
Thanks
I have loaded the views inside a grid as below,
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Entry x:Name="SearchTextBox"
Grid.Row="0"
HorizontalOptions="Fill"
Placeholder="Search"
VerticalOptions="Fill" />
<ListView x:Name="listView"
Grid.Row="1"
HorizontalOptions="Fill"
VerticalOptions="Fill" />
<local:CustomListView x:Name="customView"
Grid.Row="0"
ItemsSource="{Binding Items}">
</local:CustomListView >
</Grid>
Out of 3 views in the above code snippet, first two views are rendered properly. But the 3rd view(custom view) not rendered. CustomViews are not rendered only if I set RowDefinition as "Auto". So, anyone please tell why the custom view is not loaded if I set "Auto".
your CustomListView probably doesn't request a minimum size correctly, and as the middle row has a height of *, it takes all of the available space minus the minimum size requests.
I have a custom Expander that I've created as a template:
<local:MultiplyConverter x:Key="multiplyConverter" />
<ControlTemplate x:Key="AnimatedExpander" TargetType="{x:Type Expander}">
<DockPanel>
<ToggleButton x:Name="ExpanderButton" DockPanel.Dock="Top" Template="{StaticResource ExpanderButton}" Content="{TemplateBinding Header}" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" OverridesDefaultStyle="True">
</ToggleButton>
<ScrollViewer x:Name="ExpanderContentScrollView" DockPanel.Dock="Bottom" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Bottom">
<ScrollViewer.Tag>
<sys:Double>0.0</sys:Double>
</ScrollViewer.Tag>
<ScrollViewer.Height>
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualHeight" ElementName="ExpanderContent"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</ScrollViewer.Height>
<ContentPresenter x:Name="ExpanderContent" ContentSource="Content" />
</ScrollViewer>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ExpanderContentScrollView" Storyboard.TargetProperty="Tag" To="1" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<CubicEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ExpanderContentScrollView" Storyboard.TargetProperty="Tag" To="0" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<CubicEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
When I actually go to instantiate the Expander inside a grid, the code looks like this:
<Expander Template="{StaticResource AnimatedExpander}" ExpandDirection="Down" OverridesDefaultStyle="True" FontSize="11.0" Foreground="#CC000000" Header="Export Options" HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Border Grid.Column="0" CornerRadius="0" Background="Transparent" Margin="10,0,10,0" BorderBrush="#FFAAAAAA" BorderThickness="0,0,0,0.5">
<ComboBox Grid.Column="0" ItemsSource="{Binding CurrentSlicerManager.Exporters}" DisplayMemberPath="Name" SelectedItem="{Binding CurrentSlicerManager.SelectedExporter, Mode=TwoWay}" Grid.Row="0" Margin="0,0,0,10"></ComboBox>
</Border>
<ContentControl Content="{Binding CurrentSlicerManager}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"></ContentControl>
</Grid>
</Expander>
As you can see, I've bound the content inside the Expander to a ContentControl. The ContentControl uses a DataTemplate to determine which .xaml I should load into the Expander. So, I have two DataTemplates that look like this:
<DataTemplate DataType="{x:Type MLC:MLRasterSlicerManager}">
<local:MLRasterSlicerExportSettings></local:MLRasterSlicerExportSettings>
</DataTemplate>
<DataTemplate DataType="{x:Type MLC:MLVectorSlicerManager}">
<local:MLVectorSlicerExportSettings></local:MLVectorSlicerExportSettings>
</DataTemplate>
So, I have two .xaml files (MLRasterSlicerExportSettings and MLVectorSlicerExportSettings) which get loaded... and this works fine. The issue is that the height of these two interfaces are different. When, I change the combobox which controls which file to load into the expander, I would expect the expander to automatically resize itself. And, this does happen when it first loads the expander with the smaller height and then I switch it to load the one with the larger height value... the expander does resize itself to accommodate the larger file... but if I switch it back to the smaller one, then it never resizes to the appropriate height. It just remains the same height as the largest file. Can anyone recommend how to get this expander to automatically resize to the size of the content?
When the Complete Survey button on the Expander.Header is clicked, I would like to Navigate to another page and pass along some information from the viewmodel. I have the expander working so that when its selected it expands, and the selecteditem property is properly bound and filled. However if I just click right to the button, the selecteditem does not change and is not even populated if its the first action. How can I trigger the selected item if the button control is pressed before the expander is selected? I would prefer an MVVM solution if possible. Thanks
<ListBox x:Name="SearchList"
Grid.Row="1"
Margin="5,0,5,0"
Grid.Column="0"
Background="Transparent"
BorderThickness="0"
BorderBrush="Transparent"
ItemsSource="{Binding Path=SearchResults}"
SelectedItem="{Binding Path=SelectedResult,Mode=TwoWay,Converter={StaticResource DebugConverter}}"
HorizontalContentAlignment="Stretch"
HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<toolkit:Expander>
<sb:BindingHelper.Binding>
<sb:RelativeSourceBinding TargetProperty="IsExpanded"
Path="IsSelected"
RelativeMode="FindAncestor"
AncestorType="ListBoxItem" BindingMode="TwoWay" />
</sb:BindingHelper.Binding>
<toolkit:Expander.Header>
<Grid Width="525">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="25" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0"
Grid.Row="0"
Text="{Binding Path=PatientName}" />
<Button Grid.Column="2"
Grid.Row="0"
Content="Complete Survey">
<sb:BindingHelper.Binding>
<sb:RelativeSourceBinding Path="OpenSurveyCommand"
TargetProperty="Command"
RelativeMode="ParentDataContext" />
</sb:BindingHelper.Binding>
</Button>
</Grid>
</toolkit:Expander.Header>
<StackPanel>
<TextBlock Text="{Binding MRN,Converter={StaticResource StringLabelConverter},ConverterParameter=MRN}" />
<TextBlock Text="{Binding OriginalVisitNumber,Converter={StaticResource StringLabelConverter},ConverterParameter='Original Visit Number'}" />
<TextBlock Text="{Binding OriginalAdmitDate,Converter={StaticResource StringLabelConverter},ConverterParameter='Original Admit Date'}" />
<TextBlock Text="{Binding OriginalReason,Converter={StaticResource StringLabelConverter},ConverterParameter='Original Reason'}" />
<TextBlock Text="{Binding ReAdmitVisitNumber,Converter={StaticResource StringLabelConverter},ConverterParameter='ReAdmit Visit Number'}" />
<TextBlock Text="{Binding ReAdmitDate,Converter={StaticResource StringLabelConverter},ConverterParameter='Readmit Date'}" />
<TextBlock Text="{Binding ReAdmitReason,Converter={StaticResource StringLabelConverter},ConverterParameter='ReAdmit Reason'}" />
</StackPanel>
</toolkit:Expander>
</DataTemplate>
</ListBox.ItemTemplate>
I'm not familiar with the BindingHelper class you're using but if it's using the standard commanding in the background then I'd bind the command parameter to the "item".
That way you have access to the bound item in the commands executed event.
Using a collection of viewmodels with the button in the viewmodel solved this. No special magic other than the ObservableCollectionVM