Binding inside DataTemplate grid property to its column definitions - c#

What I need is to guaranty that all my columns aren't gonna be stretched by its content controls when they are bigger. Now it does. I found a solution here enter link description here. It works, but I'm wondering if it's possible to bind to item template Grid Width itself somehow instead of binding to the ListBox Width? And if it's possible is it proper way to go in terms of performance?
<telerik:RadListBox.ItemTemplate>
<DataTemplate>
<Grid> <-- need to bind this Grid Width
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" /> <-- to these columns width for further calculations
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

You can name the parent Grid and bind to it like:
<Grid x:Name="ParentGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Path=ActualWidth,
ElementName=ParentGrid,
Converter={StaticResource YourConverter}"/>
<!-- ... -->
</Grid.ColumnDefinitions>
<!-- ... -->
</Grid>
An other way is to bind the Grid as parent like:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Path=ActualWidth,
RelativeSource={RelativeSource AncestorType={x:Type Grid}},
Converter={StaticResource YourConverter}"/>
<!-- ... -->
</Grid.ColumnDefinitions>
<!-- ... -->
</Grid>

Related

Parent.Grid + Child.Grid => Shared ColumnDefinitions

I want to share a parent column definition with a child grid.
I have a parent grid like:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<controls:GridEntry />
<controls:GridEntry />
<controls:GridEntry />
</Grid>
and a child that is a UserControl (controls:GridEntry) with following content:
<Grid>
<Label x:Name="caption" />
<TextBox x:Name="value" />
<Button x:Name="button" />
</Grid>
My current idea is to find the parent grid from the child and set the constraints (if possible as binding, otherwise copy. When copying I have to catch all resize operations manually).
Is there an easy way to transfer the ColumnDefinitions of the parent grid to the child grid (preferably via XAML)?

Expand the Grid with when the Expander is expanded

I have a problem designing my GUI in wpf.
How do i set the Grid ColumnDefinition Width dynamically,
I have a expander. And when the expander is clicked the grid should also expand and adjust with the size of the expander
As of now i have this GUI
enter image description here
And this is the xaml code
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="127"/>
<ColumnDefinition Width="665*"/>
</Grid.ColumnDefinitions>
<Expander Background="Gray" x:Name="expander" ExpandDirection="Right" Expanded="Expander_Expanded" >
<Expander.Header>
<TextBlock Text="Objects">
<TextBlock.LayoutTransform>
<RotateTransform Angle="-90"/>
</TextBlock.LayoutTransform>
</TextBlock>
</Expander.Header>
<StackPanel Margin="10,4,0,0">
<CheckBox Margin="4" Content="Option 1" />
<CheckBox Margin="4" Content="Option 2" />
<CheckBox Margin="4" Content="Option 3" />
</StackPanel>
<!-- Stuff XD -->
</Expander>
<Grid Grid.Column="1" Background="Red"/>
</Grid>
As of now the ColomnDefinition width is 127
I want it to adjust to at least 30. So the window will be filled with other stuff
like this
enter image description here
But my problem is how do i expand the grid when the expander is expanded.
And another thing. I can't get the size of the expander when expanded. It gives me NaN which i can't use to set the columndefinition width
Thank you so much. Sorry for my bad english
Use Auto in first column Width and it will define size of expander based on content.
If you would like that column "0" has some min Width just set the property MinWidth. (but in that case I will not recommend, but show below)
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="30"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
Also I will recommend use GridSplitter, then you will have splitter between two columns that allows to change width of columns by user in UI
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="30"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="DarkSalmon"/>
Also in expander you can only have one user-control, so "stuff" you said need to be inside some layout control like stack-panel,dock or another grid etc.
Let me know if it works as you expected.

Why Image goes beyond Grid?

I'm making a program for viewing images and I met with a problem that wide pictures go beyond the window.
I set the property "stretch" to "uniform" but it doesn't work with wide pictures. What can I do?
An example of this problem:
And if I expand window it will be this
This is XAML of image:
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="300" Width="0.1*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition MinWidth="300" Width="*"/>
</Grid.ColumnDefinitions>
<TreeView Style="{StaticResource BorderStyle}" ScrollViewer.VerticalScrollBarVisibility="Auto" Name="folders" Grid.Row="0" Grid.Column="0" TreeViewItem.Expanded="treeView_Expanded">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
<StackPanel>
<Label HorizontalAlignment="Stretch" Cursor="Hand" Content="{Binding fileName}" Foreground="#FFF"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<GridSplitter Margin="-5 5 -5 5" Cursor="SizeWE" Grid.Row="0" Grid.Column="1" VerticalAlignment="Stretch" ShowsPreview="False" Width="5" HorizontalAlignment="Center" Background="Transparent"/>
<Border Style="{StaticResource BorderStyle}" Grid.Row="0" Grid.Column="2">
<Image Name="ImageViewer"/>
</Border>
</Grid>
The image is sizing itself to its parent, but the MinWidth="300" in your first and third grid column definitions is forcing the parent to be wider than the window. MinWidth overrides Width if the two disagree.
If you change to these values, it won't do that any more except when the window is too narrow to be much use anyway:
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="30" Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition MinWidth="30" Width="4*"/>
</Grid.ColumnDefinitions>
I'm not sure what you were getting at with what you had: The number/* Width values (the System.Windows.GridLength structure, whose documentation meets the usual regrettable standard of WPF documentation) work in a not immediately obvious way. The following creates three columns. The middle one is sized to its content. The first one uses one eleventh of the remaining space; the last one uses ten elevenths of the remaining space. "*" means "1*". We add all the numeric values and pro-rate the available space accordingly.
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.1*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
That's exactly equivalent to this:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="10*"/>
</Grid.ColumnDefinitions>
It's proportional.
So your MinWidth values seem wrong to me, unless you have a truly enviable monitor setup. What I've given you will make the image area four times the width of the left sidebar, which is a rough guess at what you seem to be looking for. I like those proportions.

Add ScrollViewer to only one column inside a grid

I'd like to add a scrollviewer to only 1 column in my grid, so that the left column stay fixed, while the right columns can scroll. Also, my right column is a tabpanel, i'd like to be able to scroll only the content.
This is what i currently have : but the whole page keeps scrolling.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<max:MaxListBox Margin="2" VerticalAlignment="Stretch" Width="100" x:Name="lsbYear" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Path=WorkingEntity.PayrollFormulas.Periods}"/>
<max:MaxTabControl Grid.Column="1" Margin="2">
<max:MaxTabItem FieldDescription="Enum:PayrollProvincesType.Federal">
<ScrollViewer>
<!-- content for this tab -->
</ScrollViewer>
</max:MaxTabItem>
<max:MaxTabItem FieldDescription="Enum:PayrollProvincesType.Quebec">
<ScrollViewer>
<!-- content for this other tab -->
</ScrollViewer>
</max:MaxTabItem>
</max:MaxTabControl>
</Grid>
Example :

Modify Grid of a UserControl in MainPage.xaml

I found many threads about this topic but couldn't make my app working, so I ask a new question here.
I want to make a UserControl-element that has a Grid that can be filled from outside.
this is the UserControl-Xaml-Part:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="70"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="2" x:Name="ButtonGrid"/>
</Grid>
Outside in my MainPage.xaml I want to use it like this:
<UserControls:MyControl>
<UserControls:MyControl.ButtonGrid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="130"/>
<ColumnDefinition Width="130"/>
<ColumnDefinition Width="130"/>
<ColumnDefinition Width="130"/>
</Grid.ColumnDefinitions>
// Add elements and stuff
</Grid>
</UserControls:MyControl.ButtonGrid>
</UserControls:AppBar>
But I don't get this far. It says that "ButtonGrid" was not recognized or couldn't access Member (my translation from german error-message). But when I type UserControls:MyControl. it suggests ButtonGrid.
The MyControl.xaml.cs looks like this:
namespace myApp
{
public partial class MyControl: UserControl
{
public Grid ButtonGrid { get; set; }
// or
public Grid ButtonGrid
{
get { return (Grid)GetValue(ButtonGridProperty); }
set { SetValue(ButtonGridProperty, value); }
}
public static readonly DependencyProperty ButtonGridProperty =
DependencyProperty.Register("ButtonGrid", typeof(Grid), typeof(MyControl), new PropertyMetadata(new Grid()));
public MyControl()
{
InitializeComponent();
}
}
}
I tried many ways of making this "ButtonGrid"-value visible and working but still it doesn't. Any Ideas?
EDIT
I can get the Grid in the codebehind with a simple getter. But its just not straight-forward to create stuff somewhere and THEN put them to the place I want them to be.
Setting a Name on an element in XAML creates a private field for that object that you can then access in code-behind. It does not make it a placeholder for other content as you're trying to use it. If you want to inject external content into your XAML use a ContentPresenter or some ContentControl derivative and set the content you want to inject to its Content property. This is the pattern used in general for ContentControls so you can look at the default template for Button for example and see this pattern.
So to use this:
<local:MyControl>
<local:MyControl.CustomContent>
<Grid>
<!-- elements and stuff to pass in -->
</Grid>
</local:MyControl.CustomContent>
</local:MyControl>
You would have a DependencyProperty in MyControl (CustomContent) like you tried already (but it should be type object unless you have a specific reason for some other type). Then your control's XAML would look more like:
<Grid>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="2" Content="{Binding CustomContent, RelativeSource={RelativeSource FindAncestor, AncestorType=local:MyControl}}"/>
</Grid>
Thanks to John Bowen for the right idea. Now the best solution I've got so far is:
MainPage.xaml
<local:MyControlx:Name="Control" Grid.Row="1" Grid.RowSpan="2"
Height="98" VerticalAlignment="Bottom">
<local:MyControl.Content>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="130"/>
<ColumnDefinition Width="130"/>
<ColumnDefinition Width="130"/>
<ColumnDefinition Width="130"/>
</Grid.ColumnDefinitions>
<!-- Stuff inside that works! -->
</Grid>
</local:MyControl.Content>
</local:MyControl>
And MyControl.xaml (which is a ContentControl now!):
<Grid x:Name="MyCtrl" Background="{StaticResource PhoneAccentBrush}"
Height="98" VerticalAlignment="Bottom"
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualWidth}">
<Grid.RenderTransform>
<TranslateTransform x:Name="moveTransform" />
</Grid.RenderTransform>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="70"/>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="2"
Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}"/>
<!-- Buttons and stuff that should be always there in Grid.Column=0 and Grid.Column=4 -->
</Button>
</Grid>
The buttons and stuff from MainPage.xaml are visible, clickable and nothing crashes. But I don't see the buttons or PhoneAccentBrush-background from the inside of MyControl.xaml =/
So this must be the right way I just miss something..
Edit:
If I make MyControl to a UserControl the .Content overwrites everything that was inside.
If I make it a ContentControl it seems to see the inner Grid because it places everything almost in the right place. But still I can't see any other elements that are declared inside the MyControl. If I don't set the .Content I see all internal stuff, all methods working but of course nothing that I wanted to place inside is there.
Edit2:
I've managed it somehow but stumbled into new errors. But I guess its better to link the other thread ;)
Keep a reference to objects passed to a UserControl

Categories