Sharing controls in ResourceDictionary - wpf

I have a grid that I want to share in several places, the grid has several controls (textboxes, labels, textblocks and buttons). I placed it in my ResourceDictionary like so:
<Grid Background="LightGray" x:Key="gridShare">
<!-- other controls here -->
</Grid>
But when I use it in more than one place I get an exception saying:
"Specified element is already the logical child of another element. Disconnect it first."
Which makes sense, so I'm wondering if there's any other way to achieve this.
Thanks in advance.

If I correctly understand what you're trying to do (present the exact same composite control in multiple places), you can put the grid in a ControlTemplate and apply it to ContentControls:
In the ResourceDictionary:
<ControlTemplate x:Key="frequentlyUsedTemplate">
<Grid>
[...]
</Grid>
</ControlTemplate>
In a UserControl:
<ContentControl Content="[...]" Template="{StaticResource frequentlyUsedTemplate}"/>

What you want to do is create a custom control with this as a template, then use an instance of this custom control instead of the Grid itself. Alternately create a UserControl and use instances of it.

Related

Specify content root for new base window in WPF

Is there a way to specify the "hole" for additional XAML content in WPF?
For instance if I create MySuperWindowBase and have some XAML in it with a layout, how can I specify where to place additional content in the layout in a subclass of MySuperWindowBase?
For a simplified example
MySuperWindowBase:
<Window>
<StackPanel>
<!-- Force child content here -->
</StackPanel>
</Window>
MyChildWindow:
<MySuperWindowBase>
<TextBlock>Place me in the StackPanel</TextBlock>
</MySuperWindowBase>
What you want is to give the base class window a template. Gusdor's answer explains everything but how to write a template that'll display the control's Content property, so here's an illustrative example of a control template for a window. The window's content is whatever's inside the <Window></Window> element in your ChildWindow.xaml file: <TextBlock>Place me in the StackPanel</TextBlock> is the placeholder content in your question. By default, that XAML visual tree fragment will get assigned to the window's Content property.
The ContentPresenter control presents the content. By default, it looks at the templated parent's Content property, but you can change that by setting the ContentPresenter's ContentSource property to the name of a different property of the templated parent.
<ControlTemplate TargetType="Window" x:Key="WindowBaseTemplate">
<Grid>
<Border
BorderBrush="Gray"
BorderThickness="1"
Margin="10"
Padding="20"
Background="GhostWhite"
>
<ContentPresenter
/>
</Border>
</Grid>
</ControlTemplate>
ContentPresenter looks like there must be magic, but it's just the defaults.
Create a new Style for the window -
https://code.msdn.microsoft.com/windowsdesktop/WPF-styling-a-Window-in-fcf4e4ce
Set the ContentTemplate property to include your mandatory elements.
Almost every other method will cause you to run into namescope issues at some point.

Can I combine this Dockpanel into a user control or custom control?

I have the following XAML inside a <TabItem>:
<ScrollViewer ....>
<Border ....>
<DockPanel ...>
....
</DockPanel>
</Border>
</ScrollViewer>
This same XAML is going to repeated multiple times. I'm wondering if it would be easier to create some type of UserControl or custom control (not sure user control will work). Then, if I need to change a setting on one of those 3 it would cascade to all TabItems that contain the ScrollViewer/Border/DockPanel.
You can put the abouve XAML code into a UserControl for instance, but you need to know that each time you use the user control, a diferent instace will be created. So if you want update all instaces you need to make a binding to a common INotifyPropertyChanged class property.
Hope this could helps...

Control Template that wraps another control in XAML

I want to create a custom control that extends a built-in control and then has a template that wraps that control with a container?
The C# class:
class ExtraBorderTextBox : TextBox {}
The Xaml:
<ControlTemplate>
<Border>
<TextBox/>
</Border>
</ControlTemplate>
That doesnt' work because the TextBox in the control template isn't my custom control, it is a second instance.
I need access to the properties and events on TextBox, having a different parent doens't make sense, I would have to replicate all of that in my class.
This is a simplified example; imagine Border being replaced with a ContentControl that has a 50 line control template for itself. I guess I want something like ContentPresenter (like I have in the ContentControl), but there isn't anything like a "ControlPresenter". Right? Am I missing something, or am I stuck with replicating my content control for the TextBox, or replicating the TextBox behaviour and presentation for my content control?
Thanks.
Update:
There is an answer here that does what I want, which is to copy the default template for System.Windows.Controls.TextBox. This will do what I want; I can insert my container into that. I was hoping that WPF provided a way that is more maintainable to do something like this, something like a adorner/decorator pattern.
Is there any way to make this better in some way? Would using something like Expression Blend make this so that I don't have to hand-edit the XAML pasted in from the webpage?
You could use the default control template as a base and modify it. The default control templates can be found here: http://msdn.microsoft.com/en-us/library/aa970773.aspx
If I understood you right, you want to inherit from TextBox, do some overriding, and use that new class in XAML.
If so:
1) declare the xmlns namespace at the top of your file:
<UserControl
...
xmlns:local="TheAssemblyWhereExtraBorderTextBoxResides"
...>
2) use your custom textbox:
<ControlTemplate>
<Border>
<local:ExtraBorderTextBox />
</Border>
</ControlTemplate>

WPF User Control extending border class. "Does not support direct content"?

I am producing graphics for a process control system and I would like to create a system border which would visually wrap the various sub system being displayed in the process mimic. I could use a regular border for this except I want it to not only changing color reflecting system status, but also popping up small "balloons" indicating the piece of the system that is in alarm state.
I created a test project with a User Control and added a ListBox (for the balloons) and a ContentPresenter element wrapped in a border control. However, whenever I use this new control in another app, it wont allow me to add content to it. I've tried messing some with the ContentPropertyAttribute and properties of the ContentPresenter element, but I feel I am in the blind here.
<UserControl x:Class="SystemStatusBorder.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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Canvas Height="290" Width="303">
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ContentPresenter/>
</Border>
<ListBox Canvas.Right="0" Canvas.Bottom="0">
<ListBox.RenderTransform>
<TranslateTransform X="20"></TranslateTransform>
</ListBox.RenderTransform>
<ListBoxItem>TagA</ListBoxItem>
<ListBoxItem>TagB</ListBoxItem>
</ListBox>
</Canvas>
</UserControl>
I don't get it. What more should it need other than just the existence of a contentpresenter? UserControl subclasses ContentControl so I would have thought the wiring was in place. Eventually, I want it to be used something like this:
<SystemBorder>
<SystemBorder.MonitoredTags>
<List of relevant tags for the specific sub system goes here>
</SystemBorder.MonitoredTags>
<regular content goes here>
</SystemBorder>
To create your own container control, you must create a new custom control (not a UserControl).
Make your new control inherit from ContentControl.
Custom Controls don't have their own XAML. Instead, they are assigned a ControlTemplate.
When you create your first Custom Control, the IDE will create a new file Themes\Generic.xaml.
This is where the template for your control is. You can modify this template to match the XAML in your question. This will support the ContentPresenter element.
I found a very good walkthrough here.

How to access a WPF control located in a ControlTemplate?

Usually, the WPF controls are declared in the .xaml files and not in the code behind (.xaml.cs files). However, sometimes I need to use some of those controls in code behind in order to manipulate them. How can I get the handle of such a control if it "resides" in the xaml file?
You can use the FindName() method of the ControlTemplate class.
// Finding the grid that is generated by the ControlTemplate of the Button
Grid gridInTemplate = (Grid)myButton1.Template.FindName("grid", myButton1);
I'm unsure about what you're asking, so I'll try and answer both instances that I'm interpreting as your question.
1)
If you want to declare an explicit control, and then edit it directly, all you have to do is set the name property like such:
<Canvas x:Name="myCanvas"/>
You can then access the canvas through the Name as such:
myCanvas.Background = Brushes.Blue;
2)
If you're looking to declare a generic control, and then use it multiple times, you can do it like this:
<Window>
<Window.Resources>
<Ellipse x:Key="myEllipse" Height="10" Width="10">
</Window.Resources>
</Window>
You can then access that predefined control using this syntax in code:
Ellipse tempEllipse = (Ellipse)FindResource("MyEllipse");
If you want to use the Resourse as a template for multiple controls, add x:Shared="false".

Resources