Dynamic Control Template in Silverlight - silverlight

I'm trying to make a button in Silverlight use a control template to change the way it looks.
I need to do this dynamically in code (not xaml markup).
The Button object has a Template property to which you can assign a ControlTemplate.
But how do you stuff UI elements into the ControlTemplate?
(In WPF, there is a VisualTree property but no such property exists in Silverlight)

I'm not sure if this helps, but just in case. To create buttons using a control template in code behind (not XAML) I've done it like this:
load the control template from an xml definition (below is a link to the source)
byte[] bytes = ReadBytesFromStream("BestBuyRemix.BL.buttontemplate.xml");
string buttonTemplate = "";
UTF8Encoding encoding = new UTF8Encoding();
buttonTemplate = encoding.GetString(bytes.ToArray(), 0, (int)bytes.Length);
create the button and add it to the visual tree (in this case a wrap panel)
string onebutton = string.Format(buttonTemplate, mnu.CatItemName, mnu.CatItemImage,
"{StaticResource buttonStyle1}",
"{StaticResource CatItemNameBlock}", "{StaticResource ThumbNailPreview}",
ictr.ToString());
ictr += 1;
Button bt = (Button)XamlReader.Load(onebutton);
bt.Tag = mnu.CatItemPageUri;
bt.Click += new RoutedEventHandler(bt_Click);
Wrappable.Children.Add(bt);
I wrote a post on my blog about the Best Buy Remix API which uses this to build a product list in the details page. It has a link to the Silverlight source. In case you're interested.
blog post link

Related

WPF Datagrid Button commandParameter in code behind

I'm trying to build a datagrid with columns and a button in code behind and I want to assign the command parameter of this button to the value of the "ID" column which is "TDENT_ID". Here's my code
this line is not working as you can see :
BtnDetail.SetBinding(System.Windows.Controls.Primitives.ButtonBase.CommandParameterProperty, new Binding() { Source = dtGrid, Path = "TDENT_ID" });
How can I write it?
FrameworkElementFactory:
"This class is a deprecated way to programmatically create templates, which are subclasses of FrameworkTemplate such as ControlTemplate or DataTemplate; not all of the template functionality is available when you create a template using this class. The recommended way to programmatically create a template is to load XAML from a string or a memory stream using the Load method of the XamlReader class." Microsoft Docs
Your Bindingis wrong. It currently points to the DataGrid which does not have a property TDENT_ID.
This property is on your data item, which is the DataContext of the column's template.
Therefore, correct Binding would be:
// Set up a Binding that uses the current DataContext as Binding.Source
BtnDetail.SetBinding(ButtonBase.CommandParameterProperty, new Binding(nameof(myItemType.TDENT_ID)));
Microsoft Docs: Specifying the binding source
Try to learn XAML. It makes writing such UI related code much easier, which makes you more productive.

Default MenuItem TopLevelHeader Control Template

Where can I get the MenuItem TopLevelHeader Control Template? The MSDN link for styling menu items gives a modified template.
I need to obtain a control template that contains a default pop-up/context menu.
Manny tools are available that will serve the purpose like stylesnooper and Show Me The Template
but if you have Microsoft Expression Blend you can extract the default control template by
Draggint the control onto the design
surface
Right click the control and choose
Edit Template -> Edit Copy
When you do this, Blend will extract the base template from the control and explicitly declare it within document/application as a resource which you can then edit to your liking.
Check this for more
http://www.shafqatahmed.com/2009/01/wpf-kid-stuff-extracting-a-control-template.html
I could not get Blend or the usual tools to access that control template but you can extract it yourself with code like the following:
var controlTemplate = (ControlTemplate)FindResource(MenuItem.TopLevelHeaderTemplateKey);
var sb = new StringBuilder();
var xml = XmlWriter.Create(sb, new XmlWriterSettings { Indent = true, NewLineOnAttributes = true });
XamlWriter.Save(controlTemplate, xml);
var xaml = sb.ToString();
Debug.WriteLine(xaml);
The output is too long to include here.

WPF: Add Page w/functionality into a Window at runtime as XAML

I have created a WPF app where I dynamicly build XAML elements using c# code and then add them to a root "container" grid.
What I'm trying to do is take advantage of the features in Blend and create some XAML Pages that have their own set of code behind logic, Storyboards, etc.
I want to load that XAML at runtime, however for some reason my approach is not working and I'm at a loss for why.
This what what I did before. In my root Window I create a new MyModule and add it to my contentRoot.
myModule = new MyModule();
contentRoot.Children.Add(myModule );
(Approach that works) MyModule class extends Canvas and consists of a .XAML file and .CS code behind file. The XAML is just a root canvas, and the .CS has all the logic to create elements and add them to the root canvas.
When I use this same approach where MyModule is now extends Page nothing shows up. The XAML now has a lot of content in it including a Canvas.Resources Canvas.Triggers, and a bunch of other elements.
How can I load pre-created XAML content from a Class including the code behind logic at run time?
Page and Canvas are two different kind of components in XAML.
Page is framework element, and Canvas is Container, which can have multiple controls placed with absolute x,y coordinates. Where else Page has only one property "Content" you can consider Page being an advanced content control.
Blend must have created methods related to Canvas and which will be like "Canvas.SetLeft" etc, but they will certainly not work in Page.
Your Page class must have one content of type "Canvas" and you must add all controls inside "Canvas" inside page, that shall help you.
This is the text from MSDN,
A Page can have only a single child element. All other elements on a Page must be descendents of that element. Typically, the content of a Page hosts a layout element—such as Grid, StackPanel, and DockPanel—that hosts the content of the Page.
In your case, Page should host one element "Canvas" and add items.
Or why dont you try this one, let your MyModule be same as what it is, and you create a new Page, called MyModulePage and it should look like this.
<MyModulePage>
<MyModule/> <!-- that is your canvas generated in blend -->
</MyModulePage>
I find this question a bit unclear, but here's something that worked for me.
Define MyModule as:
<Page x:Class="WpfApplication3.MyModule"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
</Page>
public partial class MyModule : Page
{
public MyModule()
{
InitializeComponent();
this.Content = new TextBlock(new Run("WOW!"));
}
}
Created a standalone file called MyModuleStandalone.xaml:
<local:MyModule xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:WpfApplication3;assembly=WpfApplication3"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</local:MyModule>
The code below works. When I show c, it displays a text block with the text "WOW!".
FileStream xamlFile = new FileStream("MyModuleStandalone.xaml", FileMode.Open, FileAccess.Read);
MyModule c= (MyModule)XamlReader.Load(xamlFile);
this.Content = c;
The local var c is an instance of MyModule so all of the code from that class is available. Is this what you're looking for?
You cannot use the x:Class attribute in your standalone XAML file because this implies the XAML is a partial class and the rest of the class is declared somewhere else. XamlReader just won't support it.
Remember that when you read in a XAML file, you are reading in a serialized object. There is no way to dynamically inject code behind into an arbitrary standalone xaml file.
FileStream xamlFile = new FileStream("Resources/News/NewsModuleCanvas.xaml", FileMode.Open, FileAccess.Read);
Canvas newsCanvas = (Canvas)XamlReader.Load(xamlFile);
contentRoot.Children.Add(newsCanvas);
Used this to load XAML, however this still does not give me the option of also adding the code behind logic.

How to Programmatically Modify a DataTemplate?

I'm trying to programmatically add events and elements to a DataTemplate in a Silverlight 3.0 app. I have a User Control with a dependency property where I would like to take the template that's set, tweak it, and then set the modified version to an inner control.
The idea I have is to take the DataTemplate that comes in, read its XAML, tweak it, and then use the XamlReader to create a modified DataTemplate that can then be set to the inner control. The issue with this approach is I don't know how to get the XAML from the originalal template (if it's even possible.) For example:
protected virtual void OnItemTemplateChanged(DependencyPropertyChangedEventArgs e)
{
// Get the original Xaml from the set template
//string originalXaml = ???
// Modify the template
string newXaml = originalXaml.Replace("foo", "bar"); // for example
// Create a new template from the modified XAML
DataTemplate newTemplate = (DataTemplate)XamlReader.Load(newXaml);
// Update the inner template
this._childDropdown.ItemTemplate = newTemplate;
}
Does someone know either: 1) if there's a way to read the original XAML, or 2) another approach to programmatically modify the DataTemplate.
Thanks,
You cannot manipulate the template via code (see documentation for FrameworkTemplate). The closest you are going to get is to call the DataTemplate's LoadContent to create an instance of the contained Xaml but you can't use that to manipulate the contents and there is no way inside Silverlight to convert a UIElement back to Xaml again.
The nearest I think you can get is to make your dependency object a Uri pointing to a Xaml resource that contains the initial DataTemplate.
You can then load this resource into an XDocument and manipulate it as XML. Subsequently you can use XamlReader to instance the DataTemplate and assign it to ItemTemplate.

How to load control template in a resource dictionary in code for a calendar control

I have a WPF calendar control and the template for the day has a property called
cal.DayTemplate =
I have created a dictionary file contaning my control template for the day of the calendar
But I am not sure how to load it into the DayTemplate property.
I have added my dictionary to the Application.Resources in App.xaml
the x:Key to my control template is x:Key="DayTemplate"
So I though to load it this would work
cal.DayTemplate = new DataTemplate("DayTemplate");
Edit: Oops. Been a while since I had to do this.
I believe you want:
cal.DayTemplate = (DataTemplate)Application.Current.FindResource("DayTemplate");
See if that works.

Resources