I'd like to move an element from one grid into another and have a problem to assign programmatically a template to the new instance. Further, details of my attempt.
For this purpose, I create an instance of the class together with its visual appearance from the template.
Inside the Window tag I declare the namespace:
xlmns:my="clr-namespace:myNameSpace"
I have a template in resources:
<ControlTemplate x:Key="templateX">
<StackPanel>
<Image Source="pic.png" Width="50" Height="50"/>
</StackPanel>
</ControlTemplate>
and place the element into the grid.
<Grid Grid.Row="2">
<StackPanel>
<my:someClass Template="{StaticResource templateX}" MouseMove="_event">
</StackPanel>
</Grid>
Now, I drag the element, the event "_event" fires. If I push a standard element (e.g. Rectangle) through this, I do the following at the end of the drag-n-drop chain of events:
Rectangle new_instance = new Rectangle();
// place for rectangle's form and color
NewPlace.Children.Add(new_instance);
// place for positioning the rectangle in NewPlace canvas
How, can I do the last part with the element of someClass? If I do
someClass new_instance = new someClass();
NewPlace.Children.Add(new_instance);
the template "templateX" isn't assigned to it.
The issue in this case seems to be that you want to combine two things:
an instance of your custom class (new_instance)
a control template available as a XAML resource
You already know how to create the instance of your class and how to add it to the Children list.
How to retrieve the control template (or for that matter, any other object) from a XAML resource has been discussed in other SO questions, e.g.:
How can I access ResourceDictionary in wpf from C# code?
Accessing a resource via codebehind in WPF
This leads to:
ControlTemplate template = (ControlTemplate)this.FindResource("templateX");
Now, the crucial point is that you do not want to add the control template itself to the Children list. The control template is just a set of instructions how to create a UI tree for your control and bind its properties to those of your control, where appropriate.
Instead, you want to configure new_instance to use the control template you retrieved from the resource. You can do that by assigning the control template to the Template property of new_instance:
new_instance.Template = template;
Once new_instance is added to Children, it will be displayed and it will use your custom control template.
Related
I have a class library, in which I've created default styles for TextBlock, which is applied to every TextBlock in any application that uses this class library.
The problem is that I sometimes need to exclude TextBlocks inside some other controls (say, ribbon, or my own Custom Control). The textblocks are not accessible, for instance the ones inside a tab item heade.
Is there any ways to force wpf to use another style for all TextBlocks inside one control?
Thanks
Simply add an empty (or any other) style to the resource dictionary of any ancestor of the TextBlock nested inside the control referencing the resource dictionary, in which the global style is defined. For instance, the global style defined for TextBlock won't be applied in this case (if the resource dictionary is referenced by an ancestor of the Button control):
<Button>
<Button.Resources>
<Style TargetType="TextBlock"/>
</Button.Resources>
<TextBlock Text="FooBar"/>
<Button>
Ok. As it turns out, this is not possible, see Mike Strobel's answer for an explanation of the reason and the rational behind it.
The workaround is to not create an implicit style for TextBlock, because it will affect TextBlocks inside other ControlTemplates.
What works for me is to derive a class from TextBlock, say Label and apply my style to it, and then use it wherever I want a TextBlock with that specific style.
A more "Wpf Natural" way to deal with that is to create a style with a key.
In .NET/WP/WPF, I am looking to create my first user control that will render content using a DataTemplate and am wondering how to do that. Do I need to use the Content presenter and pass it a reference to the template or what? Thanks for the help guys!
The basic strategy for including templated content in other fixed content (like the XAML of a UserControl) is to define a set of Content properties (as DependencyProperties) on the containing control and then add a ContentPresenter (with appropriate bindings) as the placeholder into which the content will be injected. In the framework you can see an example of this in HeaderedContentControl which has both a normal Content property set, but also a parallel set of Header properties that are used as a second piece of content.
The properties you can define on your control (differing by platform) are:
Content
ContentTemplate
ContentTemplateSelector
ContentStringFormat
with whatever your custom name is substituted for "Content" in each. In your case you probably only have the first two. Then in your UserControl layout (which is actually defining the Content itself of the UserControl) just place a ContentPresenter and set it up to use your custom properties with the control itself as the Binding Source (ElementName, RelativeSource, or setting the DataContext somewhere to the UserControl itself):
<ContentPresenter Content="{Binding ElementName=MyControl, Path=MyExtraContent}"
ContentTemplate="{Binding ElementName=MyControl, Path=MyExtraContentTemplate}" />
In most cases (but not here) ContentPresenter is used inside a ControlTemplate where you can use a nice shortcut that's built in to bind all the content properties for you:
<ContentPresenter ContentSource="MyExtraContent"/>
You can get the same effect with ContentControl but it's adding extra elements to your visual tree since it's basically just a ContentTemplate containing a ContentPresenter that passes all the properties through. It does allow you to add some visual differences, like Background or Padding, or add a whole custom template but in cases like this you can do exactly the same thing by just adding other controls around your ContentPresenter.
I am trying to write a UserControl that will allow both single controls in it (like Label), as well as "layout" controls like StackPanel and friends.
I am having trouble doing that. The code I have works for single controls, but not for layout controls. I have a feeling this is an obvious fix, I am new to WPF. Here is the UserControl XAML:
<UserControl <!-- namespaces omitted for brevity -->>
<UserControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{TemplateBinding Content}" />
</DataTemplate>
</UserControl.ContentTemplate>
</UserControl>
When I try to use it like this:
<my:SpecialUserControl>
hello
</my:SpecialUserControl>
It's fine. But when I try to do something like
<my:SpecialUserControl>
<StackPanel>
<!-- stuff -->
</StackPanel>
</my:SpecialUserControl>
I get an error in Visual Studio Intellisense saying
The specified value cannot be assigned to the collection. The following type was expected: UIElement
And when I run the app (it builds), I get this exception at that place in the XAML:
'Add value to collection of type System.Windows.Controls.UIElementCollection threw an exception.' Line number x and line position y.
What can I do to make my UserControl able to accept any type of content?
The ContentPresenter should be a part of the ControlTemplate (<UserControl.Template>) of your control, not inside your ContentTemplate. I think that could be your problem.
Inherit your UserControl from ContentControl. ContentControl already has Content property combined with ContentPresenter inside ControlTemplate.
You can also use microsoft blend to get ContentControls visual tree.
How can I add an object (in shape of rectangle for instance) to an embedded in a stack panel tag.
I was able to show the objects (as rectangle) on it using and and then using the style in an xaml file using something like:
<stackpanel ...>
<Expander Header="Controls" Content="{StaticResource FC}" IsExpanded="True"/>
</StackPanel>
but need to insert object onto toolbox dynamically. any idea how this could be done through code?
Your help will be appreciated.
Amit
Expander is a type of control which is considered to be a content type control. As such it only has one child ( the child I believe you are calling a 'toolbox') which according to your Xaml is the FC item. Do these steps to add your item to the FC item:
In Xaml give a name to the Expander so it can be accessed in code behind.
In codebehind get the expander via its name.
Access the property Content on the expander and cast it to the FC class.
Add the item you want into the FC's children or content (whatever it is you know and we don't so its my best guess).
I've created a simple WPF application which has two Windows. The user fills in some information on the first Window and then clicks Ok which will take them to the second Window. This is working fine but I'm trying to incorporate both Windows into a single Window so just the content changes.
I managed to find this Resource management when changing window content which seems like it is what I'm after. However, I've search for ContentPresenter but couldn't find much help for how I need to use it. For example, if I use a ContentPresenter, where do I put the existing XAML elements that are in the two Windows? I'm guessing the first Window will go into the ContentPresenter but the second one will need to be put somewhere for when it needs to be switched in.
Any help would be great. A simple working example would be even better.
TIA
A ContentPresenter is normally used when restyling existing controls. It is the place where the Content of a control is placed. Instead you should use a ContentControl, which is simply a control that has a content element. Alternatively, you could directly set the Content of your window.
You extract the contents of your two existing windows into two UserControls. Then you create a new Window which will host the contents. Depending on your business logic, you set the content of that window (or that window's ContentControl if you want additional "master" content) to either of those two UserControls.
EDIT:
As a starting point. This is not complete working code, just to get you started. Note that this is bad architecture; you should probably use a MVVM or similar approach once you get this running!
<Window>
<ContentControl Name="ContentHolder" />
</Window>
<UserControl x:Class="MyFirstUserControl" /> <!-- Originally the first window -->
<UserControl x:Class="MySecondUserControl" /> <!-- Originally the second window -->
In code behind of Window:
// Somewhere, ex. in constructor
this.ContentHolder.Content = new MyFirstUserControl;
// Somewhere else, ex. in reaction to user interaction
this.ContentHolder.Content = new MySecondUserControl;
I use ContentPresenter for snapping in content. In the window, I put something like this:
<ContentPresenter Content="{Binding MainContent}" />
In the view model, I have a property called MainContent of type object:
public object MainContent { get { return (object)GetValue(MainContentProperty); } set { SetValue(MainContentProperty, value); } }
public static readonly DependencyProperty MainContentProperty = DependencyProperty.Register("MainContent", typeof(object), typeof(SomeViewModel), new FrameworkPropertyMetadata(null));
Whatever you set MainContent to will show up in the window.
To keep the separation between view and view model, I typically set the MainContent property to another view model and use a data template to map that view model to a view:
<DataTemplate DataType="{x:Type viewmodels:PlanViewModel}">
<views:PlanView />
</DataTemplate>
I put that data template in some central resource dictionary along with a bunch of other view-model-to-view mappers.