I want to know how can i change user control from my Parent window that i placed usercontrol into it.
I have an user control that have a grid and data grid in that. now i want change data grid properties in my window ... and i want add another control to my grid .
some thing like this
<window>
<usercontrol>
<usercontrol.datagrid backcolor=#ff00000>
<usercontrol/>
<window/>
or can i add a textblock into usercontrol grid like this code :
<window>
<usercontrol.grid>
<textblock grid.row=1/>
<usercontrol.grid/>
<window/>
All element in user control are public so i can make change from c# code but i want do that with xaml design mode
in windows form i create a user control inherit from data grid view then i custom it. i use it in 10 windows and in 11th window i need change data grid view a bit i dont change usercontrol because it change all windows so i just change that usercontrol is in 11th window
please help !
I think you should create a DependencyProperty for your DataGrid's BackgroundColor (or whatever property you want to change) inside your UserControl's code behind:
public static DependencyProperty GridColorProperty = DependencyProperty.Register("GridColor", typeof (Brush),
typeof (UserControl1),
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions
.AffectsRender));
public Brush GridColor
{
get { return (Brush)GetValue(GridColorProperty); }
set { SetValue(GridColorProperty, value);}
}
After that you should bind your DataGrid's Color property to it in UserControl's XAML:
<DataGrid Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=YourControlType}, Path=GridColor}"/>
And now you can use the control like that:
<YourControlType GridColor="Green"/>
As for controls addition it depends on what outlook exactly you're trying to achieve. The most straightforward way would be to derive your user control from grid. Or may be deriving from ContentControl would be enough for your purposes
Edit:
That's how you could put inside a new control. Deriving your control from Grid:
<Grid x:Class="WpfApplication3.UserControl1"
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:app="clr-namespace:WpfApplication3" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<DataGrid Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=app:YourControlType}, Path=GridColor}"/>
</Grid>
And you would use it like that:
<YourControlType GridColor="Green">
<Button Grid.Row="1"/>
</YourControlType>
But actually it's a pretty weird thing to do and I would better derive it from a ContentControl:
<ContentControl x:Class="WpfApplication3.YourControlType"
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:app="clr-namespace:WpfApplication3" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<DataGrid Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=app:YourControlType}, Path=GridColor}"/>
<ContentPresenter Content="{TemplateBinding Content}" Grid.Row="1"/>
</Grid>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
That's how you use it:
<YourControlType GridColor="Green">
<Button/>
</YourControlType>
As yet another possibility you could create a dependency property for your control's content. Code behind:
public static readonly DependencyProperty InnerContentProperty =
DependencyProperty.Register("InnerContent", typeof (FrameworkElement), typeof (YourControlType),
new FrameworkPropertyMetadata(default(FrameworkElement),
FrameworkPropertyMetadataOptions.AffectsRender));
public FrameworkElement InnerContent
{
get { return (FrameworkElement) GetValue(InnerContentProperty); }
set { SetValue(InnerContentProperty, value); }
}
UserControl's XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<DataGrid Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=WpfApplication3:UserControl1}, Path=GridColor}"/>
<ContentControl Grid.Row="1" Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=app:YourControlType}, Path=InnerContent}"/>
</Grid>
Usage:
<YourControlType GridColor="Green">
<YourControlType.InnerContent>
<Button/>
</YourControlType.InnerContent>
</YourControlType>
But if you want just a quick and simple answer to your initial question as it states, there is no way you can directly address an inner control of your UserControl from XAML. = )
Related
In my project, I wanted a UserControl that can display different formats of an image (bitmap, svg), selected from a ListBox. The SelectedItem of the ListBox is bound to the appropriate view model, which in turn changes the DataContext of the UserControl, and what I want to achieve is for it to change the displaying control (an Image for bitmaps, a SharpVectors.SvgViewBox for svg files) through data templates. It does so, but raises data binding errors, as if the templates were still intact whilst the UserControl's DataContext has already been changed.
I should like to a) avoid any data binding errors even if they cause no visible problems b) understand what is happening, so I prepared a MWE, which, to my surprise, displays the same behaviour, so I can present it here.
My minimal UserControl is as follows:
<UserControl x:Class="BindingDataTemplateMWE.VersatileControl"
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:system="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<DataTemplate DataType="{x:Type system:String}">
<TextBlock Text="{Binding Content.Length, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContentControl}}" />
</DataTemplate>
<DataTemplate DataType="{x:Type system:DateTime}">
<TextBlock Text="{Binding Content.DayOfWeek, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContentControl}}" />
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentControl
Content="{Binding .}" />
</Grid>
</UserControl>
The MainWindow that references this UserControl has the following XAML:
<Window x:Class="BindingDataTemplateMWE.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BindingDataTemplateMWE"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListBox
Grid.Column="0"
SelectedItem="{Binding Selected}"
ItemsSource="{Binding Items}" />
<local:VersatileControl
Grid.Column="1"
DataContext="{Binding Selected}" />
</Grid>
</Window>
with the following code-behind (to make the MWE indeed minimal, I made the window its own DataContext, but originally there is a dedicated view model):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
namespace BindingDataTemplateMWE
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
private object selected;
public event PropertyChangedEventHandler PropertyChanged;
public List<object> Items { get; }
public object Selected {
get { return selected; }
set {
selected = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Selected)));
}
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
Items = new List<object>() { "a string", DateTime.Now, "another string" };
}
}
}
When I select a different item in the list, the desired effect takes place: the UserControl displays the length if a string is selected and the day of week when a DateTime. Still, I get the following binding error when selecting a DateTime after a string:
Length property not found on object of type DateTime.
and conversely, selecting a string after a DateTime yields
DayOfWeek property not found on object of type String.
It is clear that what I am doing is not meant to be done, but I do not know what the correct paradigm is and what happens in the background. Please advise me. Thank you.
I've seen this problem often when creating complex data templates (several levels of nesting) when views are loaded/unloaded. Honestly, some of such errors I am ignoring completely.
In your case something similar happens because you are manipulating DataContext directly. At the moment the new value is set, the previous value is still used in bindings, which monitor for source change and will try to update the target.
In your scenario you don't need this constant monitoring, so an easy fix is to use BindingMode.OneTime:
<DataTemplate DataType="{x:Type system:String}">
<TextBlock Text="{Binding Content.Length, RelativeSource={RelativeSource AncestorType=ContentControl}, Mode=OneTime}" />
</DataTemplate>
I am writing a WPF control that is meant to be a container in the same way Border and ScrollViewer are containers. It is called EllipsisButtonControl, and it is supposed to place an ellipsis button to the right of its content. Here's an example of how I intend for it to be used:
<local:EllipsisButtonControl>
<TextBlock Text="Testing" />
</local:EllipsisButtonControl>
Here is the XAML for EllipsisButtonControl:
<ContentControl
x:Class="WpfApplication1.EllipsisButtonControl"
x:Name="ContentControl"
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"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" Content="{Binding ElementName=ContentControl, Path=Content}" />
<Button Grid.Column="1" Command="{Binding ElementName=ContentControl, Path=Command}" Margin="3,0" Width="30" Height="24" MaxHeight="24" VerticalAlignment="Stretch" Content="..." />
</Grid>
</ContentControl>
And here is the code behind:
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
public partial class EllipsisButtonControl
{
public EllipsisButtonControl()
{
InitializeComponent();
}
public static string GetCommand(DependencyObject obj)
{
return (string)obj.GetValue(CommandProperty);
}
public static void SetCommand(DependencyObject obj, string value)
{
obj.SetValue(CommandProperty, value);
}
public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached(
name: "Command",
propertyType: typeof(ICommand),
ownerType: typeof(EllipsisButtonControl),
defaultMetadata: new UIPropertyMetadata());
}
}
This doesn't work. It crashes the Designer with a System.Runtime.Remoting.RemotingException.
I believe the binding on the ContentPresenter of the EllipsisButtonControl XAML is wrong, but I don't know how to make it right. What is the appropriate syntax to make that line reference the control's content? (e.g. The TextBlock defined in the usage example)
Edit:
poke provided a comprehensive answer below (including working code), but for the benefit of others who might share my initial misunderstanding, let me summarize the key concept here: A container control cannot "place content", per se. It achieves the desired effect by defining a template that modifies the way the calling XAML presents the content. The rest of the solution follows from that premise.
<local:EllipsisButtonControl>
<TextBlock Text="Testing" />
</local:EllipsisButtonControl>
This does set the Content of your user control. But so does the following in the user control’s XAML:
<ContentControl …>
<Grid>
…
</Grid>
</ContentControl>
The calling XAML has precendence here, so whatever you do inside that user control’s XAML is actually ignored.
The solution here is to set the template of the user control. The template, in this case the control’s control template, determines how the control itself is rendered. The simplest template for a user control (and also its default) is just using a ContentPresenter there, but of course, you want to add some stuff around that, so we have to overwrite the template. This generally looks like this:
<ContentControl …>
<!-- We are setting the `Template` property -->
<ContentControl.Template>
<!-- The template value is of type `ControlTemplate` and we should
also set the target type properly so binding paths can be resolved -->
<ControlTemplate>
<!-- This is where your control code actually goes -->
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
Now this is the frame you need to make this work. However, once you’re inside the control template, you need to use the proper binding type. Since we are writing a template and want to bind to properties of the parent control, we need to specify the parent control as the relative source in bindings. But the easiest way to do that is to just use the TemplateBinding markup extension. Using that, a ContentPresenter can be placed like this inside the ControlTemplate above:
<ContentPresenter Content="{TemplateBinding Content}" />
And that should be all you need here in order to get the content presenter working.
However, now that you use a control template, of course you need to adjust your other bindings too. In particular the binding to your custom dependency property Command. This would generally look just the same as the template binding to Content but since our control template is targetting the type ContentControl and a ContentControl does not have your custom property, we need to explicitly reference your custom dependency property here:
<Button Command="{TemplateBinding local:EllipsisButtonControl.Command}" … />
Once we have that, all the bindings should work fine. (In case you are wondering now: Yes, the binding always targets the static dependency property on the type)
So, to sum this all up, your custom content control should look something like this:
<ContentControl
x:Class="WpfApplication1.EllipsisButtonControl"
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:WpfApplication1"
d:DesignHeight="30" d:DesignWidth="300" mc:Ignorable="d">
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<Grid>
<ContentPresenter Grid.Column="0"
Content="{TemplateBinding Content}" />
<Button Grid.Column="1" Content="…"
Command="{TemplateBinding local:EllipsisButtonControl.Command}" />
</Grid>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
Try replacing this line:
<ContentPresenter Grid.Column="0" Content="{Binding ElementName=ContentControl, Path=Content}" />
With this
<ContentPresenter Grid.Column="0" Content={Binding Content} />
In your existing code you are making this ContentPresenter display the generated content of EllipsesButtonControl, which includes the ContentPresenter which must render the generated content of ElipsesButtonControl which includes the ContentPresenter..... Unlimited recursion.
The XAML of your EllipsisButtonControl already sets its Content to the top-level Grid. What you probably wanted is to create a ControlTemplate, e.g. like this:
<ContentControl x:Class="WpfApplication1.EllipsisButtonControl"
x:Name="ContentControl"
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"
mc:Ignorable="d" d:DesignHeight="30" d:DesignWidth="300">
<ContentControl.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0"
Content="{Binding ElementName=ContentControl, Path=Content}"/>
<Button Grid.Column="1"
Command="{Binding ElementName=ContentControl, Path=Command}"
Margin="3,0" Width="30" Height="24" MaxHeight="24"
VerticalAlignment="Stretch" Content="..." />
</Grid>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
I'm programming at this Point of time some WPF UserControls (no CustomControls!) - consisting of a handful of nested controls - and overwritting in the CS-file of the UserControl some of the inherited properties like HorizontalContentAlignment with "new".
Generally my usercontrols consist of a Border and in it per example a Label with a TextBlock as Content (for the possibility of textwrapping).
All properties are working well except the alignments.
As Long as i used my own properties p.e. "ControlHorizontalContentAlignment" it worked as expected: The Label filled the Border and the TextBlock was p.e. at bottom right.
But now with HorizontalContentAlignment overwritten, the Label don't fill the Border control anymore.
It seems to be that there is a Problem with overwritting properties like HorizontalContentAlignment.
How can i handle that problem?
My UserControl for the Label is in XAML defined like that:
<UserControl x:Class="UsercontrolExample.UserControls.ControlLabel"
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:UsercontrolExample.UserControls"
mc:Ignorable="d"
d:DesignHeight="30"
d:DesignWidth="150">
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border x:Name="border"
Style="{StaticResource usercontrolBorderStyle}">
<Label x:Name="label" Background="Yellow" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
Margin="2">
<TextBlock x:Name="textblock" Background="Orange"
Text="Label Label"
TextWrapping="Wrap"/>
</Label>
</Border>
</Grid>
</UserControl>
And the Resource usercontrolBorderStyle:
<Style x:Key="usercontrolBorderStyle">
<Setter Property="Border.BorderBrush" Value="RoyalBlue"/>
<Setter Property="Border.BorderThickness" Value="1"/>
<Setter Property="Border.HorizontalAlignment" Value="Stretch"/>
<Setter Property="Border.VerticalAlignment" Value="Stretch"/>
</Style>
This is the overwritten property:
public new HorizontalAlignment HorizontalContentAlignment
{
get { return Converter.ConvertTextAlignmentToHorizontalAlignment(textblock.TextAlignment); }
set {textblock.TextAlignment = Converter.ConvertHorizontalAlignmentToTextAlignment(value); }
}
And this was my own original property which worked:
public HorizontalAlignment ControlHorizontalContentAlignment
{
get { return label.HorizontalContentAlignment; }
set
{
label.HorizontalContentAlignment = value;
textblock.TextAlignment = Converter.ConvertHorizontalAlignmentToTextAlignment(value);
}
}
Thanks in advance!
hiding HorizontalContentAlignment property (new HorizontalAlignment HorizontalContentAlignment) is not a good idea. i think you can avoid that, if use a correct binding (new converter required)
<UserControl x:Class="UsercontrolExample.UserControls.ControlLabel"
x:Name="myLabel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot">
...
<TextBlock x:Name="textblock" Background="Orange"
Text="Label Label"
HorizontalAlignment="Stretch"
TextAlignment="{Binding HorizontalContentAlignment,
ElementName=myLabel,
Converter={StaticResource HorizontalToText}}"
TextWrapping="Wrap"/>
</Grid>
</UserControl>
HorizontalToText is an instance of converter stored in Resources
example of converter here: WPF binding HorizontalAlignment to TextAlignment
I'm new to WPF, but have been able make a lot of progress in short time thanks to a good book on the topic, and of course, quality posts on sites like this one. However, now I've come across something I can seem to figure out by those means, so I posting my first question.
I've have a ControlTemplate in a resource dictionary which I apply to several UserControl views. The template provides a simple overlay border and two buttons: Save and Cancel. The templated user control holds various text boxes, etc., and is bound to some ViewModel depending on the context. I'm trying to figure out how to bind the commands to the Save/Cancel buttons when I use/declare the UserControl in some view. Is this is even possible, or am I doing something very wrong?
First, the template:
<ControlTemplate x:Key="OverlayEditorDialog"
TargetType="ContentControl">
<Grid>
<Border HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="DarkGray"
Opacity=".7"/>
<Border HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="DarkGray">
<Grid>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0"/>
<Grid Grid.Row="1"
Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="1"
Content="Cancel"
***Command="{Binding CancelCommand}}"**
/>
<Button Grid.Column="0"
Content="Save"
***Command="{Binding Path=SaveCommand}"***/>
</Grid>
</Grid>
</Border>
</Grid>
</ControlTemplate>
The template in turn is used in the CustomerEditorOverlay user control
<UserControl x:Class="GarazhApp.View.CustomerEditorOverlay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<UserControl.Resources>
<ResourceDictionary Source="Dictionary1.xaml"/>
</UserControl.Resources>
<ContentControl Template="{StaticResource ResourceKey=OverlayEditorDialog}">
<Grid Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<SomeElement/>
<SomeOtherElement/>
</Grid>
</ContentControl>
...and finally, the user control is used as part of a view like so:
<local:CustomerEditorOverlay Visibility="{Binding Path=CustomerViewModel.ViewMode, Converter={StaticResource myConverter}, FallbackValue=Collapsed}"
d:IsHidden="True" />
So, based on what I've learned from a project I have been on forever and a half, we have a workable pattern.
Let's say you have a bunch of modal windows that all get applied the same style within the application. To have Save and Cancel buttons on each view, the UserControl used for all of the modal windows has several dependency properties. In addition, we specify virtual methods for your commands (e.g. OnSaveCommand, OnCancelCommand, CanExecuteSaveCommand, CanExecuteCancelCommand) and the commands themselves as properties in a base ViewModel that is inherited by your views.
Ultimately, what happens is we create new modal windows by simply doing this:
<my:YourBaseView x:class="MyFirstView" xmlns:whatever="whatever" [...]>
<my:YourBaseView.PrimaryButton>
<Button Content="Save" Command="{Binding SaveCommand}" />
</my:YourBaseView.PrimaryButton>
<!-- some content -->
</my:YourBaseView>
With accompanying code-behind:
public class MyFirstView : YourBaseView
{
[Import] /* using MEF, but you can also do MvvmLight or whatever */
public MyFirstViewModel ViewModel { /* based on datacontext */ }
}
And a ViewModel:
public class MyFirstViewModel : ViewModelBase
{
public override OnSaveCommand(object commandParameter)
{
/* do something on save */
}
}
The template for this UserControl specifies ContentControls in a grid layout with the Content property bound to the PrimaryButton and SecondaryButton. Of course, the content for the modal is stored in the Content property of the UserControl and displayed in a ContentPresenter as well.
<Style TargetType="{x:Type my:YourBaseView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type my:YourBaseView}">
<Grid>
<!-- ignoring layout stuff -->
<ContentControl Content="{TemplateBinding Content}" />
<ContentControl Content="{TemplateBinding PrimaryButton}" />
<ContentControl Content="{TemplateBinding SecondaryButton}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
UserControl code:
public class YourBaseView : UserControl
{
public static readonly DependencyProperty PrimaryButtonProperty =
DependencyProperty.Register("PrimaryButton", typeof(Button), typeof(YourBaseView), new PropertyMetadata(null));
public Button PrimaryButton
{
get { return (Button)GetValue(PrimaryButtonProperty); }
set { SetValue(PrimaryButtonProperty, value); }
}
/* and so on */
}
You can change the style for each instance of your templated view, of course. We just happen to stick with one base style.
TL;DR edit: I may have gone a bit overboard since I think you just need the understanding that exposing dependency properties of type Button which are set up through the XAML each time you create a new overlay. That, or you could probably RelativeSource your way back up to the visual tree with something like {Binding DataContext.SaveCommand, RelativeSource={RelativeSource AncestorType={x:Type MyView}}} but it's a little dirtier.
I'm developing Windows Store App with using Caliburn Micro.
In one of the pages I have ContentControl, which display UserControl. In UserControl I have GridView. My question is: How to set UserControl.Width same as ContentControl.Width? Note: whet set UserControl.Width=Auto - width the same as GridView.Width
in page.xaml
<ContentControl x:Name="ActiveItem" />
in usercontrol.xaml
<UserControl
x:Class="Test.Views.GroupView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Width="Auto" Height="Auto">
<Grid Margin="0,20">
<GridView x:Name="Groups" Margin="0" />
</Grid>
</UserControl>
UPDATE
Adding
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
To UserControl doesn't solve the problem.
Figured this out after a lot of trial and error:
<ContentControl Name="MyContent" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
The key is to use the Horizontal/Vertical*Content*Alignment property (not the Horizontal/VerticalAlignment properties).
Here is what you should do when problem like your's appears.
Try to set ContentControl's Background property to some disturbing color. For example Purple or Pink. And also set Background property on your UserControl for example Green. It will allow you to see where exactly is your ContentControl and where is UserControl. If you can't see any Green you can tell that content of UserControl is stretched to fill whole UserControl.
Try to set UserControl's VerticalAlignment and HorizontalAlignment properties to Stretch. FrameworkElement.HorizontalAlignment, VerticalAlignment
Note: In order to let these work. You can't explicitly set Width and Height on your UserControl.
Try to set ContentControl's VerticalContentAlignment and HorizontalContentAlignment to Stretch. Control.HorizontalContentAlignment, VerticalContentAlignment . These stretches the child element to fill the allocated layout space of the parent element.
If you still see some Purple or Pink then something's wrong again :) you can check Margin/Padding MSDN
If it's still messed up. Then I don't know how else can I help you. Last possible solution would be binding. And I am not sure if it works.
<UserControl
Width="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type ContentControl}},
Path=ActualWidth}"
Height="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type ContentControl}},
Path=ActualHeight}">
...
</UserControl>
I hope something helps. I believe you that it could be really annoying problem.
Especially for #AlexeiMalashkevich
I solve it with using binding like this:
In root Page you have:
<ContentControl x:Name="ActiveItem"/>
Then add the child page:
<Page
Height="{Binding ActualHeight, ElementName=ActiveItem}"
Width="{Binding ActualWidth, ElementName=ActiveItem}"
......
/>
And that's all.
You should be able to bind UserControl's width to the ContentControl's ActualWidth.
<local:MyUserControl1 Height="50" Width="{Binding ElementName=contentControl, Path=ActualWidth}"/>
Here is some sample code:
<Page
x:Class="stofUserControlWidth.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:stofUserControlWidth"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="Cyan"/>
<ContentControl Grid.Column="1" x:Name="contentControl">
<local:MyUserControl1 Height="50" Width="{Binding ElementName=contentControl, Path=ActualWidth}"/>
</ContentControl>
</Grid>
</Page>
Here is MyUserControl1.xaml code:
<UserControl
x:Class="stofUserControlWidth.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:stofUserControlWidth"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid Background="Magenta">
</Grid>
</UserControl>
Hope this helps!
For me this is working:
<UserControl
...
Height="{Binding ActualHeight,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentControl}}}">
...
</UserControl>
You have to make sure that your ContentControl has the desired size.
For example my ContentControl look like this: It is always fill the whole size of the window. And the size of the UserControl in the ContentControl dinamically changes as well.
<Grid>
<ContentControl HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" DataContext="{Binding StartViewModel}" Name="ContentArea" />
</Grid>