how to find a control inside ItemsPanelTemplate in wpf? - c#

I am trying to access a Grid inside the DataTemplate while the ItemsControl is binded by ItemsSource.
this is the full XMAL code, How do i find a certain element from outside?
for (int i = 0; i < allViewControl.Items.Count; i++)
{
var container = allViewControl.ItemContainerGenerator.ContainerFromItem(allViewControl.Items[i]) as FrameworkElement;
var grid = allViewControl.ItemTemplate.FindName("grid", container) as DataGrid;
}
i found this always returning null ?
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ItemsControl x:Name="allViewControl" Focusable="False" HorizontalContentAlignment="Center"
Grid.IsSharedSizeScope="true" ItemsSource="{Binding AllClassCharacters}"
ItemTemplate="{StaticResource CharacterViewModelTemplate}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Extensions:AnimatedWrapPanel IsItemsHost="true" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
<DataTemplate x:Key="CharacterViewModelTemplate" DataType="{x:Type ViewModel:CharacterViewModel}">
<Grid x:Name="grid" Width="200" Height="Auto" MinHeight="115" Margin="1" MinWidth="130" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RenderTransformOrigin="0.5,0.5" Background="#66000000" >
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ProgressBar x:Name="playerProgressBar" VerticalAlignment="Top" Background="Transparent" Height="5" Width="Auto" Value="0" Visibility="Collapsed" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan ="2" Grid.RowSpan="2" Foreground="White" BorderThickness="0" Style="{DynamicResource ProgressBarStyle1}" />
</Grid>

Short answer is that you shouldn't need to do this - using MVVM should give you simpler solutions to whatever you're trying to achieve.
If you need it for some niche cases like setting the focus, search for 'find control wpf' on so - there are some existing questions (example) to hack and get controls out of the WPF UI Tree

Related

Why UserControl isn't filling VerticalContentAlignment 'Stretch'?

Here is the parent Xaml:
<Grid VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*" /><!-- Should stretch vertically -->
</Grid.RowDefinitions>
<DockPanel Grid.Row="0">
<!-- Menu definition removed for brevity -->
</DockPanel>
<DockPanel Grid.Row="1"
VerticalAlignment="Stretch"
LastChildFill="True">
<ItemsControl DockPanel.Dock="Top"
ItemsSource="{Binding Designer}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
Background="YellowGreen"/>
</DockPanel>
</Grid>
The ItemsSource binding is to an ObservableCollection. When the view is added to the collection, it gets updated in the main shell (view). Here is the UserControl that is added:
<UserControl x:Class="Prototype.StateMachineDesignerApp.Views.ProjectDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Prototype.StateMachineDesignerApp.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="500"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
Margin="0">
<Grid VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="0"
BorderBrush="DimGray"
BorderThickness="1"
Background="LightSlateGray"
Margin="1" />
<Border Grid.Row="1"
Margin="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="3" />
<ColumnDefinition Width="5*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0"
BorderBrush="DarkGoldenrod"
BorderThickness="1" />
<GridSplitter Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
<Border Grid.Column="2"
BorderBrush="DarkGoldenrod"
BorderThickness="1" />
</Grid>
</Border>
</Grid>
</UserControl>
The UserControl is not filling the entire vertical space:
Row[1] of the outermost Grid is stretching vertically as is evidenced by the ItemsControl.Background filling the area.
For reference, this is what I am expecting:
For what its worth, I've looked at numerous questions on SO regarding this exact issue but none of the solutions seem to help. Then again, none of the examples I saw used an ItemsControl with binding.
This happens because the ItemsControl throw all of our items into a vertically aligned StackPanel by default. It's very easy to change though, since the ItemsControl allows you to change which panel type is used to hold all the items.
<ItemsControl DockPanel.Dock="Top"
ItemsSource="{Binding Designer}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
Background="Transparent">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

How to resize controls at runtime in WPF

There is DockPanel with three child controls placed side by side in a horizontal manner:
1) TreeView
2) RichTextBox
3) Grid
RichTextBox lies in middle of TreeView and Grid. I made RichTextBox the last child of DockPanel and set LastChildFill attribute to True. Now since Grid can be closed at run time, I want the RichTextBox to occupy all the space that became empty after the Grid is closed. But if the Grid is again shown the RichTextBox should contract from Right hand side to allow the Grid to fit in. How to achieve this? I'm new to WPF. Also, how to hide the Grid? Here is the XAML.
<DockPanel Grid.Row="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" LastChildFill="True">
<Border BorderThickness="1" DockPanel.Dock="Left" Height="Auto" HorizontalAlignment="Stretch" Margin="1" VerticalAlignment="Stretch" Width="Auto" CornerRadius="0" BorderBrush="#FF646464">
<TreeView Name="TV" Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Border>
<Border Name="Notification_Pane" BorderThickness="1" DockPanel.Dock="Right" Height="Auto" HorizontalAlignment="Stretch" Margin="1" VerticalAlignment="Stretch" Width="Auto" CornerRadius="0" BorderBrush="#FF646464">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Content="Notification" Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Top" Background="LemonChiffon" Grid.Row="0" Grid.Column="0"/>
<Button Name="btn_Close" Content="X" Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="LemonChiffon" Height="Auto" Width="Auto" Grid.Row="0" Grid.Column="1" Padding="10,0,10,0" BorderThickness="0" Cursor="Hand" Focusable="True" IsHitTestVisible="True" ClickMode="Release" Click="Button_Click" />
<ScrollViewer Height="Auto" Name="ScrollViewer" Width="Auto" Margin="0" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
<StackPanel CanVerticallyScroll="True" Height="Auto" Name="Notification_Panel" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</StackPanel>
</ScrollViewer>
</Grid>
</Border>
<Border BorderThickness="1" Height="Auto" HorizontalAlignment="Stretch" Margin="1" VerticalAlignment="Stretch" Width="Auto" CornerRadius="0" BorderBrush="#FF646464">
<RichTextBox Name="rtb" Height="Auto" Width="Auto" Grid.Row="2" HorizontalAlignment="Stretch" Grid.Column="1" Margin="0" />
</Border>
</DockPanel>
You can use Grid.Visibility property to show and hide the grid.
The following code should do the job:
private void Button_Click(object sender, RoutedEventArgs e) //X Button click event.
{
//grid is the name of our Grid Control we want to hide.
grid.Visibility = System.Windows.Visibility.Collapsed;
}
to show the grid again you should use the following code:
grid.Visibility = System.Windows.Visibility.Visible;
The RichTextBox control will always fit in the DockPanel Control.

Extracting data templates in user controls

There are known problems for setting up caliburn binding in DataTemplates.
In this answer EisenbergEffect suggests extracting Data Templates into a user control.
How can this be achieved?
In my user control I have lots of DataTemplates and ran into those problems. Conventions are not applied and I have to use "classical" Binding.
I could only imagine to extract the whole control with the DataTemplate, this would give me lots of smaller controls, but I see no way to only extract the DataTemplate.
Here is an example XAML
<Grid>
<Grid.Resources />
<Grid.RowDefinitions>
<RowDefinition Height="10*" />
<RowDefinition Height="2*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Border HorizontalAlignment="Stretch"
BorderBrush="Transparent"
BorderThickness="0">
<ScrollViewer HorizontalContentAlignment="Stretch"
Background="Yellow"
BorderBrush="Transparent"
BorderThickness="0"
CanContentScroll="True"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<!-- Conventions work here -->
<ListView x:Name="Computers"
HorizontalContentAlignment="Stretch"
Background="Red"
BorderThickness="0">
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0">
<ListView HorizontalContentAlignment="Stretch"
Background="Black"
ItemsSource="{Binding HardwareComponents}"> <!-- Conventions to not work here -->
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="Aquamarine"
BorderBrush="DarkGray"
BorderThickness="1">
<Grid Background="Transparent" cal:Message.Attach="[Event MouseDown] = [Action Expand($dataContext)]" >
<Grid.RowDefinitions>
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Border BorderBrush="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<!-- Even more DataTemplates come here -->
</Border>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</Border>
</Grid>

ScrollViewer does not react to the Grid.Row position

My StackPanel and ScrollViewer seem to just not end at the Grid.Row position. I am making a Metro app so it is mandatory for the grid to be dynamic, as well as all the elements.
The code:
<Grid Background="#FFE4E4E4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.5*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*"/>
<RowDefinition Height="0.5*"/>
</Grid.RowDefinitions>
<!--News/Leaderboard Feed-->
<StackPanel Grid.Column="0" Grid.Row="0">
</StackPanel>
<!--Marketplace Feed-->
<StackPanel Grid.Column="0" Grid.Row="1">
</StackPanel>
<!--Detailed Marketplace Account-->
<StackPanel Grid.Column="1" Grid.Row="1">
</StackPanel>
<!--Marketplace View-->
<StackPanel Grid.Column="1" Grid.Row="0" VerticalAlignment="Top">
<ScrollViewer VerticalAlignment="Top">
<!--Allows scrolling-->
<GridView x:Name="MarketplaceFeed" ItemsSource="{Binding StockList}" ItemTemplate="{StaticResource MarketplaceFeedTemplate}" VerticalAlignment="Top">
<!--Displays the stock markets the user is interested in.-->
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</ScrollViewer>
</StackPanel>
</Grid>
You should put the ScrollViewer on the outside. This will auto-fit to the grid, and anything inside it will get the scrolling treatment.
<!--Marketplace View-->
<ScrollViewer VerticalAlignment="Top" Grid.Column="1" Grid.Row="0">
<StackPanel VerticalAlignment="Top">
<!-- other content -->
</StackPanel>
</ScrollViewer>

WPF DataGrid Scrollbar

I'm trying to make a WPF DataGrid show scrollbars when necessary.
You can see the basic XAML code of my user control below:
<Grid x:Name="Data" Grid.Column="0" VerticalAlignment="Stretch" Height="Auto" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Expander Header="Route Setup" Grid.Row="0" VerticalAlignment="Top" Background="White">
</Expander>
<Expander Header="Select Locations" Grid.Row="1" VerticalAlignment="Top" Background="White">
</Expander>
<DataGrid Grid.Row="2" ItemsSource="{Binding Locations, Mode=TwoWay}" Height="Auto" AutoGenerateColumns="False" ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto">
</DataGrid>
This isn't working, I don't see any scroolbars when the DataGrid grows beyond the available space. I've already tried to use a scrollview around my DataGrid but that doesn't change anything.
Update
It might be important to know that the usercontrol is loaded into the LeftRegion of a shell that has the following markup:
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions >
<ColumnDefinition Width="*" MinWidth="400" MaxWidth="600"/>
<ColumnDefinition Width="9" />
<ColumnDefinition Width="*" MinWidth="300" />
</Grid.ColumnDefinitions>
<GridSplitter x:Name="MainSplitter" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Grid.Column="1"
Margin="0" Width="9" Style="{DynamicResource gridSplitterVerticalStyle}"/>
<ItemsControl Name="LeftRegion" Grid.Column="0" Background="Azure" Height="Auto" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" cal:RegionManager.RegionName="LeftRegion">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ItemsControl Name="RightRegion" Height="Auto" Background="DarkGreen" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" Grid.Column="2" cal:RegionManager.RegionName="RightRegion">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
Best Regards
Jay
In your grid named "Data", remove the Height="Auto" from the third RowDefinition. At least one row must have the "*" height (which is the default) to take the remaining available space.
Solved it. I needed to remove Height="Auto" from the thrird RowDefinition.

Categories

Resources