Is it good idea to mix ControlTemplate with user control? - wpf

Is it possible and a good idea to have user control (public MyControl: UserControl) which supports both ControlTemplates and existing content? I have understood that ControlTemplates should only be used when you inherit from Control (public MyControl: Control), but I found out that you can use them with UserControl too if your UserControl.xaml is empty.
Imagine I have control which has two rectangles side by side like the following:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid ShowGridLines="true" Height="100" Width="100">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle Name="left" Grid.Column="0" Height="90" Fill="LightBlue"/>
<Rectangle Name="right" Grid.Column="1" Height="100" Fill="LightGreen"/>
</Grid>
</Page>
I would like the user of the control be able to replace those rectangles with whatever FrameworkElements he wants to use. So I need a ControlTemplate.
But in 99% of the cases user of the control is happy with the existing functionality so I would like him to be able to say:
Code behind:
mycontrol.Left.Fill = ....
XAML:
<mycontrol>
<mycontrol.Left.Fill = "Red"/>
</mycontrol>
That doesn't seem to be possible since if I support control templates I really don't have any UI elements or xaml. I only have the code behind file. I guess I could have a DependencyProperty Left but as long as I don't have some kind of container which would hold the content that would't do much good. I would have to create the grid in code behind file. Doesn't seem like a good idea.
And finally I would like to be able to use generics so the user can specify the type of the parts:
MyControl mycontrol<TLeft, TRight> = new MyControl<Rectangle, Button>();
This would help in code behind because of the type safety (no need to cast FrameworkElement into correct type). Unfortunately I don't think generics are really supported on the XAML side.
Is there any solution to this problem or is it really "Inherit from Control in order to support ControlTemplates but lose the easy usability of the control. Inherit from UserControl in order to support easy usability but lose the ControlTemplate support"?

Add a dependency property to the control:
public static DependencyProperty LeftFillProperty = DependencyProperty.
Register("LeftFill", typeof(Brush), typeof(MyControl));
public Brush LeftFill
{
get { return (Brush)GetValue(LeftFillProperty); }
set { SetValue(LeftFillProperty,value); }
}
Then in the default control template use:
<Rectangle Name="left" Grid.Column="0" Height="90" Fill="{TemplateBinding LeftFill}"/>
This will left you use (C#)
ctrl.LeftFill = Brushes.Red;
or (XAML)
<c:MyControl LeftFill="Red"/>
when you use the default template and when someone writes a new control template it's their responsibility to decide what to do with the LeftFill property (or to ignore it completely).
BTW, you should consider changing the names from "left" and "right" to something else ("MasterPanel" and "DetailPanel", "FoldersArea" and "FilesArea", whatever the logical usage in your control is), this will solve the issue of someone replacing the default template with a template that displays the same data in a different layout (top and bottom instead of left and right for example).

Related

WPF- Binding properties in a DataTemplate

I'm building a window with a set of rows that share the same layout, but their contents should be different, eg:
| (Label Content:)"Name1" | (Textbox Text)"SomeText" |
| (Label Content:)"Name5" | (Textbox Text)"OtherText" |
I've defined a DataTemplate which basically holds a Grid specifying the size of each column, holds all the elements it requires (a few labels, textboxes, etc.) and sets their common properties.
<UserControl.Resources>
<DataTemplate x:Key="AxisRangeEntry" x:Shared="False">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
....
</Grid.ColumnDefinitions>
<Label x:Name="MyLabel" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center">
...
<TextBox x:Name="MyTextbox" Grid.Column="2" Width="110" HorizontalContentAlignment="Right" />
...
</Grid>
</DataTemplate>
</UserControl.Resources>
Then in my window I start adding the data template as ContentControls in a stack panel:
<ContentControl ContentTemplate="{StaticResource AxisRangeEntry}" />
<ContentControl ContentTemplate="{StaticResource AxisRangeEntry}" />
....
I'm struggling to figure out how I can define certain properties of controls inside the DataTemplate to be bindable to, and bind them to a static value/external property when I start defining the ContentControls. Effectively each ContentControl would need to be able to define things like it's MyLabel content and MyTextbox text.
I've previously created CustomControls, which had DependencyProperties on them, which I could then bind to when adding them on another window. With a DataTemplate however I'm not sure how I would define these fields as bindable and bind to them when including a new version of the template.
Any help would be appreciated.
From what it sounds like, you are not using the MVVM pattern.
For your situation, I'd recommend using MVVM -- take a look at this article for a quick intro for something that would fit your case (ItemsControl with an ItemTemplate)
What you would do is create an ObservableObject to represent each row, and then bind the collection of ObservableObjects to an ItemsControl's ItemsSource, with the ItemTemplate set to the DataTemplate you created. In the DataTemplate, you would specify each binding to the property on the ObservableObject's row, and WPF would bind to the correct instance for each row.
http://www.wpf-tutorial.com/list-controls/itemscontrol/
Either way, DataTemplates are primarily used for templating a certain data-type. If you really need to implement the view in this way, a custom UserControl with dependency properties would be the way to go.
You present a dynamic nature of items to be bound, so this answer will attempt to provide guidance within the parameter's set.
...[to] define certain properties of
controls inside the DataTemplate to be bindable to,
Within a template the binding will default to the parents data context. Simply saying {Binding} will default to that item in the data context. If the bound item has a specific property then use {Binding MyPropertyName}. Just verify that the parent, or its ancestors have a valid data context.
Think of data templates in its final location, as if you had hard coded it there. It will behave the same....
and bind them to a static value/external property when I start defining the
ContentControls.
Since this sounds like it is in a custom control, the datacontext will be the ultimate consumer's datacontext and most likely the datacontext will be worthless.
If it is on a custom control, then use named binding and bind it to a property on the control. For example the control's name, in XAML, is given the name "MyControl" (x:Name="MyControl")and in the template binding, one can path directly to it such as
{Binding MyCustomControlDependencyProperty, ElementName=MyControl}
created CustomControls, which had Dependency properties
With the above rules one can still, and should IMHO, use dependency properties of the custom control to pass on the information from the consumer to the the datatemplate which will use it dynamically..

Class Dependencies WPF Control

WPF is really amazing for many reasons and one of them is that it allows us to change the controls inside a control. As example if we take a ListBox. We can change the panel from StackPanel to WrapPanel and it will still work (I guess its obviously that ListBox and WrapPanel don't share any class dependencies hence why it works).
Here is an example what I mean with class dependencies.
public class Test1
{
public Test2 t;
public Test1(Test2 t)
{
this.t = t;
}
}
public class Test2
{
public string someStr;
}
Now the instance could be injected/inserting like this:
Test2 test2 = new Test2();
test2.someStr = "Hello";
Test1 test1 = new Test1();
test1.t = test2;
Or instance could be inserted like this:
Test2 test2 = new Test2();
test2.someStr = "Hello";
Test1 test1 = new Test1(test2);
There are few other ways to do this but I hope that you guys now get the point.
So now after we know how to inject the instance lets try to do so in WPF with this following example:
I have a CustomControl. My CustomControl is a little bit complex because it has rows and columns. Futhermore the CustomControl is not derivering from a DataGrid. In fact it is derivering from an ItemsControl.
As I mentioned it has columns and rows or to be more precise the rows need to know about the columns. Thats where I would like to insert the instance of columns in a row. How do i do that in WPF?
Here is a simple plain example of my problem:
Lets say the VisualTree of the CustomControl looks like this:
CustomControl
+ Grid
+ Border
+ ContentPresenter
+ Headers
+ DockPanel
+ Border
+ ContentPresenter
+ Rows
As you can see the Rows are far away from Headers and I would like to get/insert the instance of Headers to the Rows without finding the Headers.
Rows and Headers classes look like this:
class Row : ContentControl
{
List<Column> Headers;
...
}
class Headers : ContentControl
{
List<Column> Cols = new List<Column>()
public Headers()
{
this.Cols.Add(...);
this.Cols.Add(...);
}
...
}
And the problem is how to do something like this:
this.rows.Headers = columns.Cols;
I have searched on the internet and many people have suggested me to let the row use VisualTreeHelper and then to travel up the tree to find the Cols. In fact I tried to do so and after monitoring my CustomControl with a Performance Profiler Tool, I figured that it's exactly the step where every row stumbles up the tree to find header that takes the most of the time. Therefore lets not use VisualTreeHelper and lets use injection like I described in example with Test1 and Test2 above.
Any suggestions? Is there maybe a pattern for this?
EDITED: #Benjamin. To use RedSlider = GetTemplateChild("RedSlider") inside the OnApplyTemplate is a great solution but it doesnt work for me because my case is more complex. In my case i really need to insert the instance somehow. Here is an example of my case where I cannot use GetTemplateChild inside the OnAppyTemplate method.
This is Control for Sliders.
class CustomSliders : ContentControl
{
}
The style for CustomSlider looks like this:
<Style x:Key="mySliders" TargetType="{x:Type local:CustomSliders}">
<Style.Setter Property="Template">
<ControlTemplate TargetType="{x:Type local:CustomSliders}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Slider x:Name="PART_RedSLider" />
<Slider x:Name="PART_GreenSlider" Grid.Row="1"/>
<Slider x:Name="PART_BlueSlider" Grid.Row="2"/>
<Slider x:Name="PART_AlphaSlider" Grid.Row="3"/>
</Grid>
</ContentTemplate>
</Style>
And this is the ControlTemplate of my CustomControl called ColorPicker.
<ContentTemplate TargetType="Picker">
<DockPanel>
<ContentControl DockPanel.Dock="Left" Style="{StaticResource mySliders}"/>
<Rectangle x:Name="PART_ColorPresenter"
DockPanel.Dock="Right"
Margin="5"/>
</Grid>
</ControlTemplate>
In this example the GetTemplatedChild method which will be executed inside OnApplyTemplate of ColorPicker wont work because it cannot find the PART_RedSLider which is inside CustomSliders.
GetTemplateChild cannot find everything down the VisualTree.
Because GetTemplatedChild wont work to solve this complex template structure many people suggest me to travel recrusivly up or down the tree by using the VisualTreeHelper.Find(). Though like I explained in the question I dont want to use the recrusive way. I want to insert the instance..
As I have already stated, Kent Boogaarts answer is technically correct but I think you probably require more information to aid your understanding.
Imagine the control you are writing is a colour picker. The control has 4 Sliders for changing the red, green, blue and alpha values and the end result is displayed beside the sliders in a Rectangle. A mock-up is shown below:
This control has 5 dependencies in order for it to work correctly; 4 Sliders and 1 FrameworkElement for displaying the end result.
What this means is that in my ControlTemplate I am expecting to see 4 sliders and 1 FrameworkElement that are named. The slider that controls the red value, for example, could be called "PART_RedSlider" (the name can be anything you want but the recommended approach is to prefix the name with "PART_").
An example template may look something like this:
<!-- Typically this would be defined in a style -->
<ControlTemplate TargetType="ColorPicker">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Slider x:Name="PART_RedSLider" />
<Slider x:Name="PART_GreenSlider" Grid.Row="1"/>
<Slider x:Name="PART_BlueSlider" Grid.Row="2"/>
<Slider x:Name="PART_AlphaSlider" Grid.Row="3"/>
<Rectangle x:Name="PART_ColorPresenter"
Grid.Column="1"
Grid.RowSpan="4"
Margin="5"/>
</Grid>
</ControlTemplate>
Now in your controls code you would override the OnApplyTemplate() method, like so:
public override void OnApplyTemplate()
{
RedSlider = GetTemplateChild("PART_RedSlider") as Slider;
GreenSlider = GetTemplateChild("PART_GreenSlider") as Slider;
BlueSlider = GetTemplateChild("PART_BlueSlider") as Slider;
AplhaSlider = GetTemplateChild("PART_AlphaSlider") as Slider;
ColorPresenter = GetTemplateChild("PART_ColorPresenter") as FrameworkElement;
}
You now have access to the named parts of your ControlTemplate. You can then do whatever you want to these controls in your code (set default property values, hookup event handlers, etc).
Now you may be wondering where the TemplatePartAttribute comes into all this. The thing is, this attribute is purely for documentation purposes so that tools (such as Expression Blend) can assist other people creating a custom template.
The attribute is applied to the class you are writing like so:
[TemplatePart(Name="PART_RedSlider", Type=typeof(Slider)]
[TemplatePart(Name="PART_GreenSlider", Type=typeof(Slider)]
[TemplatePart(Name="PART_BlueSlider", Type=typeof(Slider)]
[TemplatePart(Name="PART_AlphaSlider", Type=typeof(Slider)]
[TemplatePart(Name="PART_ColorPresenter", Type=typeof(FrameworkElement)]
public class ColorPicker
A piece of advice is to never assume that the template will include a named part. Your control should still function (to the best of it's ability) without the named part being present. The guidance from Microsoft is that you should not throw exceptions if a named part is missing (I.E. your application can still run even though your control will not work as expected).
E.G.
public override void OnApplyTemplate()
{
RedSlider = GetTemplateChild("RedSlider") as Slider;
if (RedSlider != null)
{
// Only do anything if the named part is present.
}
}
You should also try to use the lowest base class possible for named parts. E.G. in my example, the named parts for the Sliders could be of type RangeBase rather than Slider so that of types of range controls can be used.
Finally, your class should have variables that hold references to your named parts which are retrieved during the call to OnApplyTemplate. Do not try and find the controls each time you want to use them.
So now you need to apply this to your control which is dependant on the Row and Header controls so these need to be present in your ControlTemplate (I will assume a single Row and Header for simplicity).
First of all document your CustomControl with the TemplatePartAttribute like so:
[TemplatePart(Name="PART_Header", Type=typeof(Header)]
[TemplatePart(Name="PART_Row", Type=typeof(Row)]
public class CustomControl : Control
{
// etc...
Now make sure you have these controls as named parts in your ControlTemplate like so:
<ControlTemplate TargetType="CustomControl">
<Grid>
<!-- other elements omitted -->
<Header x:Name="PART_Header" />
<Row x:Name="PART_Row" />
</Grid>
</ControlTemplate>
And then you use the OnApplyTemplate() method like this:
public override void OnApplyTemplate()
{
myHeader = GetTemplateChild("PART_Header") as Header;
myRow = GetTemplateChild("PART_Row") as Row;
if ((myHeader != null) && (myRow != null))
{
myRow.Headers = myHeader.Cols;
}
}
If your custom control has specific requirements regarding its visual tree, you can declare these using TemplatePartAttributes and use resolve them during OnApplyTemplate.

Skinning Control Backgrounds - Better Performance?

sorry if this question is overly simple, but I'm having a hard time figuring out how to create backgrounds to controls - in the hopes that it will improve app performance.
I have 9 different controls. All of them have a background. The backgrounds are made up of either images, other controls or both. All of those backgrounds have another background.
Think of this like Power Point with slides, slide layouts and slide masters - inherited in that order. I have 9 slides / controls.
The first 3 controls have the same "control layout" (let's call it
ControlLayout1). ControlLayout1 gets some of it's elements from ControlMaster1.
The second 3 controls also have the same control layout, but it is
different from the first. Let's call it ControlLayout2. It also
inherits from ControlMaster1.
The final set of 3 controls are different again. We can call them
ControlLayout3. But this time, they inherit from a different master - ControlMaster2.
Right now in each control I'm writing out all the XAML each time separately. I'm thinking there must be a way to not write these in each of these each item. Ideally, what I would like to create is one set of XAML that can be reused.
Here's some pseudo-XAML:
<UserControl x:Name="Control1">
<MyBackground (ControlLayout1)/>
</UserControl>
<UserControl x:Name="Control2">
<MyBackground (ControlLayout2)/>
</UserControl>
<UserControl x:Name="Control3">
<MyBackground (ControlLayout3)/>
</UserControl>
And then somewhere for ControlLayouts (I don't know, like Application.Resources or elsewhere)
<Canvas x:Name="ControlLayout1">
<MyMasterBackground (ControlMaster1)/>
</Canvas>
<Canvas x:Name="ControlLayout2">
<MyMasterBackground (ControlMaster1)/>
<TextBox Text="The Control 2">
</Canvas>
<Canvas x:Name="ControlLayout3">
<MyMasterBackground (ControlMaster2)/>
<TextBox Text="The Control 3">
</Canvas>
And then for the ControlMasters
<Canvas x:Name="ControlMaster1">
<Canvas.Background>
<ImageBrush ImageSource="/Images/image1.jpg" />
</Canvas.Background>
</Canvas>
<Canvas x:Name="ControlMaster2">
<Canvas.Background>
<ImageBrush ImageSource="/Images/image2.jpg" />
</Canvas.Background>
<TextBox Text="Control Master 1">
</Canvas>
Once defined, the ControlLayouts and ControlMasters never need to change - they are static.
Beyond just having a smaller XAP if I can put these all in one location and reuse the XAML, I'm hoping performance will be improved in my app as the ControlLayouts automatically get BitmapCached or something like that.
So first, is there a good strategy to implement the above (the ControlLayouts and Masters do not have any code-behind)? Secondly will performance be improved in loading of Control1, Control2, etc.? Finally, if they were pure usercontrols (i.e. they had some code behind), would that be better for performance?
Thanks in advance!
What you ask for is a combination of a few things:
About the Background thing: just create a dependency property (let's call it MyBackgroundDP) of type Brush in the code behind of a UserControl, and bind it to your XAML like:
<UserControl ...>
<Grid Background={"Binding MyBackgroundDP, RelativeSource={RelativeSource Mode=FindAncestor, AncestoryType=UserControl}}">
<!-- More XAML declarations -->
</Grid>
</UserControl>
To create the dependency property, you can use the built in snippet in visual studio: propdp
Simply write "propdp" and that TAB twice. Fill up the fields and it's all good.
Alright so that was easy enough, right? ;)
Now the tougher part: making so-called master pages.
Actually it's not that much different from the background thing.
Declare another dependency property, only this time of type object, or FrameworkElement (better).
Then in your XAML, you declare a kind of placeholder: ContentControl. Let's call it MyContentDP for this example:
<UserControl ...>
<Grid Background={"Binding MyBackgroundDP, RelativeSource={RelativeSource Mode=FindAncestor, AncestoryType=UserControl}}">
<ContentControl ContentTemplate="{Binding MyContentDP, RelativeSource={RelativeSource Mode=FindAncestor, AncestoryType=UserControl}}" />
</Grid>
</UserControl>
You can then fine tune whatever else you want to provide in this "master view", add a border around the Grid, put some flowers, you name it.
Once you're done, this is how you use it, assuming it was called MyUserControl
<Window ...
xmlns:local="...reference_to_your_usercontrol_dll/exe">
<Grid>
<local:MyUserControl MyBackgroundDP="Red">
<local:MyUserControl.MyContentDP>
<!-- More XAML declarations here -->
</local:MyUserControl.MyContentDP>
</local:MyUserControl>
</Grid>
</Window>
Now the performance point:
If you put all the XAML for this as a Custom control (which is DIFFERENT from a UserControl), you can then put all the XAML in your App.xaml
Why? because parsing XAML can be an intensive operation, and if you make WP7/SL parse it at runtime whenever you need it, you lose performance.
Instead, your App.xaml gets parsed at startup, then it's in memory. That's what's done in the loading of your application. You would get a performance boost, although it would be minimal for controls made of few XAML, it is still a good practice.
Hope this helps,
Bab.

Split one big XAML in number of Sub-XAML files

In my WPF4 Desktop-based application there is a big block with sidebar menu that repeats in each window and takes about 70 lines of XAML. In order to improve code reuse, I would like to split XAML file in two files:
XAML-file that contains code for sidebar menu (≈70 lines)
Base XAML file that contains «include/reference» to XAML-file with sidebar menu code
As I understood, there are two ways to implement my problem:
Use ResourceDictionary
Use UserControl/CustomControl
My questions:
What is the difference between ResourceDictionary and UserControl? Could you give me examples where I have to use UserControl and where ResourceDictionary?
Could you give a full code example how to include/import content of one XAML-file to other?
P.S. Here is an example of code that I want to export to separate XAML-file:
<Border Style = "{StaticResource Body_SideBarMenu_Border_Settings}">
<StackPanel Style = "{StaticResource Body_SideBarMenu}">
<TextBlock Style = "{StaticResource Body_SideBarMenu_Title}"
Text = "{x:Static res:Resources.WinApp_SideBarMenu_Title}" />
<TextBlock x:Name = "SideBar_WinReports"
Style = "{StaticResource Body_SideBarMenu_Item}"
Text = "{x:Static res:Resources.DashListMarker}">
<Hyperlink KeyboardNavigation.TabIndex = "12"
Style = "{StaticResource Body_SideBarMenu_Item_Hyperlink}"
Click = "Call_WinReports_Click">
<TextBlock Text = "{x:Static res:Resources.WinApp_ModuleName_Reports}" />
</Hyperlink>
</TextBlock>
</StackPanel>
</Border>
ResourceDictionary is just a container for your styles/templates etc. So you really have a choice between using a style (and referencing it through a ResourceDictionary) or a UserControl.
In order to differentiate between the two, ask yourself a question: are you implementing just another look for some existing control, or you are implementing something really new, which is more than just a ListView (or a Border, or a ComboBox etc.)? In the former case, use a style; in the latter, create a new UserControl.
Specifically for your case, I would go for a UserControl.
Code example (although not full)
(Please note that a template for the following code can be inserted with VS's "add new UserControl")
Xaml:
<UserControl x:Class="SomeNamespace.SidebarMenu"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources> <!-- you can define local styles here -->
<Style x:Key="SidebarMenuTextblock" TargetType=TextBlock>
...
</Style>
</UserControl.Resources>
<Border Background=...>
<StackPanel>
<TextBlock
x:Name="Put_a_name_if_you_want_to_reference_this_item_in_code_behind"
Style="{StaticResource SidebarMenuTextblock}"
Text="{x:Static res:Resources.WinApp_SideBarMenu_Title}" />
...
</StackPanel>
</Border>
</UserControl>
.cs:
using System;
using System.Windows;
using System.Windows.Controls;
namespace SomeNamespace
{
public partial class SidebarMenu : UserControl
{
public NumericUpDown()
{
InitializeComponent();
}
...
// define here your properties etc,
}
}
Now, you can use the control like that:
<Window
x:Class="SomeOtherNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:SomeNamespace">
<Grid>
<controls:SidebarMenu PropertyIfYouDefinedOne="SomeValue"/>
...
</Grid>
</Window>
If you can get your hands on Expression Studio, in Expression Blend, you can simply right click on any control and convert it to an user control. As easy as that.
User controls are good for splitting the XAML file. In essence, it is used to redefine the behavior of an existing control.
However, with User Controls, you can define whole WPF Layout Controls and convert them to an User Control, with the children content inside them. This is very helpful for a project spread across multiple developers, and can also be used to emulate the behavior of an MDI, which is kind of absent in WPF.

Silverlight: Nested containers and Binding

The Scenario Bit:
On one of the controls within my Silverlight application I have embedded a custom user control. Within this embedded control is another custom user control that contains a datagrid. I would like to use binding to populate the datagrid. Easy enough I just sepcificy a collection that is in the DataContext of the parent control.
Parent Form:
<UserControl x:Class="ParentControl"
...>
<Grid x:Name="LayoutRoot" >
<ReusableControl />
</Grid>
</UserControl>
Parent Codebehind:
public partial class ParentControl: UserControl
{
public ParentControl()
{
InitializeComponent();
this.DataContext = ObjectCollection;
}
public ObservableCollection<object> ObjectCollection
{
get ;
set ;
}
}
Intermediate Form
<UserControl x:Class="ReusableControl"
...>
<Grid x:Name="LayoutRoot" Background="Gold">
<CustomDataGrid />
</Grid>
</UserControl>
Child Control:
<UserControl x:Class="CustomDataGrid"
...>
<Grid x:Name="LayoutRoot">
<data:DataGrid x:Name="dgItems"
AutoGenerateColumns="True"
ItemsSource="{Binding ObjectCollection}"
>
</data:DataGrid>
</Grid>
</UserControl>
The Question Bit:
I want to specificy the columns of the datagrid dynamically, based on another collection in the parent control DataContext. How can I do this? Is there more than one way of skinning this cat?*
Thanks,
Mark
*No cats where harmed during the asking of this question.
After many hours I have found a work-around which I have posted here. This doesn't strike me as the best solution in the world, but it works, and doesn't need the registration of event handlers throughout the application. Also it works top down, which is what I wanted.
I suspect that I could use Dependency Properties a little better, to prevent the need for DP's and NP's in the same class, but I'm out of time :-(
Hope this helps someone else.

Resources