Modify Grid of a UserControl in MainPage.xaml - c#

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

Related

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.

GridSplitter not working

Trying to use GridSplitter but it's not working. Dragging the splitter to the left is fine, but dragging to the right has no effect. I think the Right grid is the problem. But I'm not sure. Please give me some advice.
Here is my code:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="{DynamicResource DefaultMargin}"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="100"/>
<ColumnDefinition x:Name="columnDefinition_One" Width="{DynamicResource DefaultMargin}"/>
<ColumnDefinition x:Name="columnDefinition_Two" MinWidth="230" Width="{Binding ActualWidth, ElementName=Element1}"/>
</Grid.ColumnDefinitions>
<Grid x:Name="Layout" Grid.Row="2" Grid.Column="0">
</Grid>
<GridSplitter x:Name="gridSplitter" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ResizeDirection="Columns" ResizeBehavior="PreviousAndNext" Grid.Column="1" Grid.Row="2" Background="{StaticResource DarkGray}" />
<Grid x:Name="grid_MonitoringView" Grid.Row="2" Grid.Column="2" Style="{DynamicResource DefaultPanel}" HorizontalAlignment="Stretch">
<Border>
<view1:ViewExample x:Name="viewExample"/>
</Border>
</Grid>
</Grid>
I copied your code into my demo project, and it works fine for me. #lomed found that you might have an incorrect MinWidth value and I agree with that too. But you say that your 'grid_MonitoringView' has not been affected.
Do you notice that my right border layout correctly? So the real problem is ViewExample class. Your ViewExample has incorrect layout values such as MinWidth or other visuals inside with larger layout width.
the GridSplitter cant reduce width of column than their MinWidth value.
You'll see it works fine if you maximize the window,
or for demostartion try remove the MinWidth value:
<ColumnDefinition />
<ColumnDefinition x:Name="columnDefinition_One" Width="50"/>
<ColumnDefinition x:Name="columnDefinition_Two"/>

Binding inside DataTemplate grid property to its column definitions

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>

XAML StackPanel inner items size problems

I have this XAML code:
<StackPanel Orientation="Horizontal" Margin="0">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel x:Name="Miniaturas" Orientation="Vertical" MinWidth="100" Width="Auto" Grid.Column="0" Height="Auto" ScrollViewer.CanContentScroll="True">
</StackPanel>
</ScrollViewer>
<Grid Margin="1">
<WindowsFormsHost x:Name="VistaPrevia" Width="Auto"/>
</Grid>
</StackPanel>
What I'm trying to do is simulate two columns. Why? because WindowsFormsHost Can't be stored into ColumnDefinition it throws this error:
Can't add value Type "WindowsFormHost" to a dictionary or collection of type "ColumnDefinitionCollection.
Usually I Do this with this code:
<Grid Margin="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<WindowsFormsHost x:Name="VistaPrevia" Width="Auto"/>
</Grid>
How can I do to obtaind the same efect without using ColumnDefinition
Note: I need two columns one with fixed width size and another that uses the remaining width of the window.
Pull down VS2013 express and see if that error has been fixed in the parser. Also verify you have installed update 4 for Visual Studio 2012 to see if it fixes the issue.
The error you have seen occurs because you did something like this
<Grid Margin="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/>
<WindowsFormsHost x:Name="VistaPrevia" Width="Auto"/><!-- fail -->
</Grid.ColumnDefinitions>
</Grid>
P.S.: and the answer is use Grid.

Button on title of ChildWindow (Silverlight) design issue

I'm designing Silverlight ChildWindow and I met one intersting problem. I defined a button on a window title as follows:
<ChildWindow.Title>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="This is textblock" Grid.Column="0"/>
<Button Content="Help" Name="btnHelp" Grid.Column="1" Width="100"
Margin="300,0,0,0" />
</Grid>
</ChildWindow.Title>
This window is resizable. When you try to resize the window, the "btnHelp" button is covered by the close button, and the "btnHelp" button is not aligned to the edge of the window also. I tried before to use a StackPanel, also I used margins in both variants (StackPanel and Grid) and they didn't help me properly. The variant in the code is latest:) Could you please give a hint, what can I do with that?
Thanks in an advance.
This is a result of what appears to be a strange choice in the ChildWindow's control template -- the Title content is not stretched, so you can't really right-align anything without hard-coding it. So, you could go ahead and just apply fixed widths to the Grid column widths:
<controls:ChildWindow.Title>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBlock Text="This is textblock" Grid.Column="0"/>
<Button Content="Help" Name="btnHelp" Grid.Column="1" />
</Grid>
</controls:ChildWindow.Title>
That's quick-and-dirty, but not very satisfying. An alternative would be to modify the ControlTemplate (at the link above) so that it behaves how you would expect. Find the ContentControl that displays the Title, and make it stretch to fill the available space, by adding HorizontalContentAlignment="Stretch":
<Style TargetType="controls:ChildWindow" x:Key="MyChildWindowStyle">
<!-- etc ... -->
<ContentControl Content="{TemplateBinding Title}" FontWeight="Bold"
HorizontalContentAlignment="Stretch"
HorizontalAlignment="Stretch" IsTabStop="False" Margin="6,0,6,0" VerticalAlignment="Center"/>
<!-- etc ... -->
</Style>
This allows you to use the normal layout controls like Grid, and it will render as expected:
<controls:ChildWindow Style="{StaticResource MyChildWindowStyle}"
...
<controls:ChildWindow.Title>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="This is textblock" Grid.Column="0"/>
<Button Content="Help" Name="btnHelp" Grid.Column="1" Width="100"/>
</Grid>
</controls:ChildWindow.Title>

Categories