Create Silverlight Control that can be used as the layout root - silverlight

How can I create a control in silverlight that can be used as the layout root, but still have a "Template" property so I can wrap the users content inside another control using a style?
My current implementation is close, it takes the content that the user places in the control and wraps it but the user has to put a grid or panel in if there is multiple controls for the content.
--Update --
This is the code I'm using that will not work as the rootlayout for multiple children unless the user puts a grid around their content. If I inherit from Grid or Panel I get an error about the DefaultStyleKey property not being available.
public class BusyControl :ContentControl
{
public BusyControl()
{
this.DefaultStyleKey = typeof(BusyControl);
}
}
<Style TargetType="local:BusyControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:BusyControl">
<telerik:RadBusyIndicator DisplayAfter="0:0:0.5" IsBusy="{Binding IsBusy}" BusyContent="{Binding BusyMessage}">
<ContentPresenter Content="{TemplateBinding Content}" Margin="{TemplateBinding Padding}"/>
</telerik:RadBusyIndicator>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This is how I want the user to be able to use my new control with out having to wrap their content in a panel or grid.
<cdc:BusyControl x:Name="BusyControl">
<some:Control x:Name="Control1" />
<some:Control x:Name="Control2" />
</cdc:BusyControl>

Seems to me that what you want is to derive your control from an ItemsControl not a ContentControl. In any ControlTemplate that you use you can place the controls using an ItemsPresenter instead of the ContentPresenter you would have used in a ContentControl.

You can have your control inherit from Panel if you want it to be able to have multiple children. You will have to handle laying out the panel's child controls if you do this. See this MSDN article on creating custom panels.
You can then specify your Template and stick the user content into the template.

I think that if you want multiple controls, i.e. children, as content then you have to use some sort of panel, which is the base class for the .Children property.
Not sure if this is applicable to your situation. I had trouble grasping exactly what's going on in your question. Maybe you can make a custom user control that inherits from ContentControl. As you may or may not know, custom user controls need a default style key. With a custom user control you need to define a template in the default style. Now the template can have a ContentControl somewhere inside of it and its content property should be template binding to the contentcontrol.content property. Or you can override the OnContentChanged function and do whatever you want in that override function (like put a single object in the control by itself... or for multiple objects create a new grid/panel and then set the objects as the grid/panels children for the user and then do what ever it is you are doing with the grid/panel. You would have to set/bind the content property on your new control. Make sense?
I don't know about your error with the default style key, and i don't have any telerik controls, but couldn't you just inherit from your telerik busy indicator? Would something like this work for you, (or put you on the right track).
protected override void OnContentChanged( object oldContent, object newContent )
{
//I dont know how you are assigning content,
//but i would say if it's IEnumerable and count is > 1 it should use your panel
var newMultiContent = newContent as System.Collections.IEnumerable;
if ( newMultiContent!=null && newMultiContent.Cast<object>().Count()>1)
{
var myNewContentContainer = new StackPanel();//or grid or whatever
myNewContentContainer.Children.Clear();
//add children
foreach (var item in newMultiContent.OfType<UIElement>())
myNewContentContainer.Children.Add(item);
//instead of the old content that wasn't what you wanted, use the new content container
base.OnContentChanged( oldContent, myNewContentContainer );
//or maybe try this and call the base method at the beginning...
Content = myNewContentContaint
}
else
base.OnContentChanged( oldContent, newContent );
}

Related

Binding Parent's property to child's readonly property [duplicate]

I'm trying to access a user control which is inside the control template of a content control. Specifically:
<ContentControl x:Name="MyList" >
<ContentControl.Template>
<ControlTemplate x:Name="MyControlTemplate">
<Border RenderTransformOrigin="0,0" x:Name="border">
<UserControls:MyControl x:Name="MyControlName" Width="100" ViewModel="{Binding}" />
I can access this.MyList but it says this.MyControlName is not found. How do I access the MyControlName object from code-behind in this situation?
Thanks!
You need to get the template and locate the control by name on the templated control, something like:
var template = MyList.Template;
var myControl = (MyControl)template.FindName("MyControlName", MyList);
Templates are just that: Abstract descriptions of what is to be created, the controls in templates only exist in the context of something that is being templated.
Note that you should only ever access the elements within a control template if you are authoring the control that the template is for. Access from outside should be done via bound properties and methods.
For data templates this is similar. All the things you need to access should be bound to an object and access should then be through said object. This is especially true in cases of item controls which virtualize their items, so the elements do not even exist most of the time.
U also can get control from every template by adding Loaded event in control and then in code assign sender of event to some variable.

WPF Catch Focus Change of Children Controls

Is there a way for a UserControl to catch focus change on any of its children controls?
I've got a TabControl which has a UserControl on each tab. I am trying to maintain focus on control items when switching between tabs.
You can subscribe to the LostFocus event of each control within the usercontrol.
To automatically do this, you can subscribe on the on initialize and loop through children. However, you'll either need to know your children directly (as in they are member variables), or your usercontrol will have to be/contain an ItemsControl.
If you contain an items control from a template, you'll have to search for the template control using the name you assigned the part.
<ControlTemplate>
<Grid x:Name="PART_ChildrenContainer">
<ItemsPresenter> <!--This will contain your children-->
</Grid>
</ControlTemplate>
Then you'll have to do the following.
var grid = (Grid)this.Template.FindName("PART_ChildrenContainer",...);
foreach(var child in grid.Children)
{
child.PreviewLostKeyboardFocus +=
new System.Windows.Input.KeyboardFocusChangedEventHandler(eventHandler);
}

WPF: Create a custom control without rewriting the ControlTemplate

Hey, I am creating a Custom Control i WPF inheriting from the ListView. However, I want it to look exactly as the already existing ListView.
Is there a way To use the default ListView Template in a Custom Control without rewriting it in xaml? I do have a Generic.xaml file with the new control added, but I should no need to rewrite the template code.
Thanks
EDIT: I also want to keep it as DRY as possible without repeating (making a mess) the code.
If you subclass the ListView, them your subclassed control will use the ListView Template. That's it! You do not have to do anything!
The Template used by a control is defined by its DefaultStyleKey dependency property. If you want to change the template of your control, set this property as follows:
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl),
new FrameworkPropertyMetadata(typeof(MyControl)));
However, if you do not set this property, it will use the value set by the superclass.
I think the problem is that you have used "Add New Item" => "Custom Control" to create you control then changed the class it extends. Instead of doing this, just add a new C# class and extend ListView.
<Style TargetType="{x:Type local:MyControl}" BasedOn={StaticResource {x:Type ListView}}" />

How do I bind a command to e.g. the right mouse button in a ControlTemplate in WPF?

I have a custom Control derived class and a view model to go with. The user can do several actions with this control, and I'm thinking it's best to implement these as RoutedCommand objects or ICommand derived objects in the view model so the ControlTemplates can bind to them. Binding a command to a button in one ControlTemplate should be straightforward, but how can I bind the command to e.g. the right mouse button in another ControlTemplate? Probably a MouseGesture is involved, but I'm having a hard time fitting the pieces together.
A MouseGesture is involved, but you don't have to explicitly construct it. You can use a MouseBinding which will construct a MouseGesture for you under the hood.
You need a UIElement to attach your binding to. Here is how you would do it with a separate decorator.
<ControlTemplate ...>
<Decorator>
<Decorator.InputBindings>
<MouseBinding MouseAction="RightClick" Command="..." />
</Decorator.InputBindings>
... content here ...
</Decorator>
</ControlTemplate>
More likely your ControlTemplate uses a Panel such as a DockPanel or Grid for layout, in which case you could attach the binding to that instead of adding a Decorator.

Custom TabItem in TabControl

I've created CustomTabItem which inherits from TabItem and i'd like to use it while binding ObservableCollection in TabControl
<TabControl ItemsSource="{Binding MyObservableCollection}"/>
It should like this in XAML, but i do not know how change default type of the output item created by TabControl while binding.
I've tried to create converter, but it has to do something like this inside convertin method:
List<CustomTabItem> resultList = new List<CustomTabItem>();
And iterate through my input ObservableCollection, create my CustomTab based on item from collection and add it to resultList...
I'd like to avoid it, bacause while creating CustomTabItem i'm creating complex View and it takes a while, so i don't want to create it always when something change in binded collection.
My class extends typical TabItem and i'd like to use this class in TabControl instead of TabItem.
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type local:CustomTabItem}">
<Setter Property="MyProperty" Value="{Binding xxx}"/>
</Style>
</TabControl.ItemContainerStyle>
Code above generates error that Style cannot be applied to TabItem.
My main purpose is to use in XAML my own CustomTabItem and bind properties... Just like above...
I've also tried to use
<TabControl.ItemTemplate/>
<TabControl.ContentTemaplte/>
But they are just styles for TabItem, so i'll still be missing my properties wchich i added in my custom class.
You will need to create a custom class derived from TabControl and override GetItemForContainerOverride to return your custom TabItem:
protected override DependencyObject GetContainerForItemOverride()
{
return new CustomTabItem();
}

Resources