How to set Control Template in code? - c#

I have this in XAML
<ControlTemplate TargetType="{x:Type Button}">
<Image ...>
</ControlTemplate>
I want to achieve same in C# code. How can I achieve this?
ControlTemplate ct = new ControlTemplate();..
Image img = new Image();..
Now how to assign this Image to Control template? Can we do this or Am I missing any concept here?

Creating template in codebehind is not a good idea, in theory one would do this by defining the ControlTemplate.VisualTree which is a FrameworkElementFactory.
ControlTemplate template = new ControlTemplate(typeof(Button));
var image = new FrameworkElementFactory(typeof(Image));
template.VisualTree = image;
Assigning properties is very roundabout since you need to use SetValue and SetBinding:
image.SetValue(Image.SourceProperty, ...);
Also, about the (previously) accepted answer and the stuff quoted:
Setting the ControlTemplate
programmatically is just like using
XAML because we have to use the
XamlReader class.
That statement is just wrong, we do not "have to".
If i assign templates at run time i define them as a resource which i can load if i need it.
Edit: According to the documentation FrameworkElementFactory is deprecated:
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.
I wonder if this recommendation is such a good idea. Personally i would still go with defining the template as a resource in XAML if i can avoid doing it with strings and the XamlReader.

http://www.eggheadcafe.com/sample-code/SilverlightWPFandXAML/73fdb6a2-6044-4c43-8766-afa12618ddc1/set-controltemplate-programmatically.aspx
Setting the ControlTemplate
programmatically is just like using
XAML because we have to use the
XamlReader class. For example, here is
the code to set a button's template,
assuming that we want to set a
button's template after it is loaded.
private void Button_Loaded(object sender, RoutedEventArgs e) {
var button = sender as Button;
string template =
"<ControlTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
TargetType=\"Button\">" +
"<Border>" +
"<ContentPresenter/>" +
"</Border>" +
"</ControlTemplate>";
button.Template = (ControlTemplate)XamlReader.Parse(template);
}
Since we used a string for specifying
the XAML code for the template, we can
use the XamlReader's Parse method. The
XamlReader also has a Load method,
which is primarily used for streams or
XAML or XML readers. Notice that we
have to include the XML namespace
http://schemas.microsoft.com/winfx/2006/xaml/presentation
because the ControlTemplate, Border,
and other controls we need are defined
there. If we did not include it, we'll
encounter a runtime exception.
Basically, we have to put the
namespaces needed by the template.

If you need to change the button image only then you can do one thing.
Create a dependency property which will represent when you want to
change the image (a bool) or may be you can create an enum which has
all possible images say
Enum Images { Image1 = 0, Image2 = 1, Image2 = 3}. Create a dependency property "CurrentButtonImage" of this type which will be associated with button.
Now in XAML use this in button template
On property Change of CurrentButtonImage update the image of button (in code behind) using
CurrentImagePropertyChangedhandler(....,...)
{
switch(CurrentButtonImage)
{
case "Image1" :
this._ButtonImage.Fill = (DrawingBrush)csd.FindResource("Image1DrawingBrush");
break;
}
}

Related

Is there a way to use a DataTemplate to define the structure of a Border object that's created in code?

So I'm currently trying to learn how to use bindings and DataContext to simplify how my app is structured.
I have a lot of dynamically created controls in my app that I create at runtime in C#, such as this simple border with a textbox inside. The data comes from data classes that I created, EntryData in this case.
Data class
class EntryData : INotifyPropertyChanged
{
public string EntryID { get; set; }
public string Title { get; set; }
public string ColourHex { get; set; }
}
Creating the control and putting it into a grid
Border outer_border = new Border();
outer_border.Tag = cur_entryData.EntryID;
outer_border.Background = GetSolidColorBrushFromHex(cur_entryData.ColourHex);
outer_border.Style = Application.Current.Resources["bor_EntryCalendarBlock"] as Style;
TextBlock txtblc_title = new TextBlock();
txtblc_title.Style = Application.Current.Resources["txtblc_CalendarBlockTitle"] as Style;
txtblc_title.Text = cur_entryData.Title;
//never got the binding to update
//txtblc_title.DataContext = cur_entryData;
//Binding bind_title = new Binding();
//bind_title.Source = cur_entryData;
//bind_title.Mode = BindingMode.TwoWay;
//bind_title.Path = new PropertyPath("Title");
//bind_title.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
//txtblc_title.SetBinding(TextBlock.TextProperty, bind_title);
outer_border.Child = txtblc_title;
Grid.SetRow(outer_border, entry_row);
Grid.SetColumn(outer_border, entry_col);
my_grid.Children.Add(outer_border);
You can see my attempt at using binding on the control, which would work to create it, but would never update when the EntryData was changed so I abandoned that. So to say update the title I go to the correct index in my_grid.Children, extract the border, extract its child textblock, and then change the text property to the new value.
This is clunky as hell to create and update all these controls but I don't know any other way. I've read a bit about using datacontents to style the entries in buttons and listviews, but I want Border (or technically Grid) as the outer layer as it makes this type of control easier to create and modify.
Is there a way to do something like this
xaml
<Page.Resources>
<DataTemplate x:Key="control_template_test" x:DataType="local:EntryData">
<TextBlock Text="{x:Bind Title}"/>
</DataTemplate>
</Page.Resources>
C#
Border new_border = new Border();
new_border.ContentTemplate = this.Resources["control_template_test"] as DataTemplate;
new_border.DataContext = cur_entryData;
I was able to get this working with a button, but not a border or grid, I assume as the button has a .Content property. Also even with the button I wasn't able to get the textblock to update when the EntryData was updated. Also I want to put details into the Border itself, such as use the tag for keeping the entryID, for easy access, and the background colour; I don't know how that would be accomplished with a DataTemplate.
Can anyone give me some help? I've tried searching for a couple hours now and haven't found anything that explains if this is possible.
EDIT:
To clarify, I understand this attempt at using ContentTemplate on a Border likely won't exist. I am looking for help at achieving something similar with a different solution. Say I create a template control which has a border and a textblock, and whenever I want I can just create one with a databinding to a data class. Ideally this data binding would update whenever the data class is updated, but that just wouldn't update when I tried before.

how i can make button like this in windows forms c#

How i can make this buttons with icons like these ??
Normally, in order to create stylized buttons in Winforms, you have to work with the Button.Image property:
this.myButton.FlatStyle = FlatStyle.Flat;
this.myButton.Image = // your image
// ...
The buttons in your image include a text, but since the enumeration System.Windows.Forms.TextImageRelation (used in the property Button.TextImageRelation) does not allow for a text below the image... obtaining the same style with this approach risks to become a hard task (using GDI, handling painting events, creating a derivative of the Button class, etc...), unless there is a trick that I don't know.
The fastest and simplest way to recreate the same style is to create a button with empty Text property and manually include the text in the image file. Actually, you set:
this.myButton.FlatStyle = FlatStyle.Flat;
this.myButton.ImageAlign = ContentAlignment.MiddleCenter;
this.myButton.Text = "";
and you put this image (just an example) straight into the control:

Named WPF control can't be found when added procedurally

We are using a third party editing control (TxTextControl) that has various toolbars and other controls which can be attached to it. This is done by placing the toolbars somewhere in the view and associating them by name. It looks something like this:
<tx:RulerBar x:Name="rulerBar"/>
<tx:TextControl RulerBar="rulerBar"/>
This works fine when defined in XAML, but we have a scenario where we need to build this procedurally. For some reason when we try associate the RulerBar (or any other toolbars/controls) it throws an error that it can't locate the toolbar. For example:
DockPanel dock = new DockPanel();
dock.Children.Add(new RulerBar { Name="rulerBar" });
dock.Children.Add(new TextControl { RulerBar = "rulerBar" });
I have also tried adding Loaded event handlers and deferred the RulerBar association until both controls were fully loaded but I still get the same error. Should this simply work, or is there some trick I'm missing? Unfortunately name association is the only mechanism they provide, and we can't associate the controls by reference.
In WPF, the XAML parsing process associates the value of an element's x:Name attribute with its name, enabling lookup by name.
So why does assigning the Name property in XAML work? This is since the Name property is marked with an attribute which instructs the parser to treat it like it treats an x:Name attribute.
Since you do not implement the same logic as the xaml parser does, you will have to do some additional coding in order for your code to work..
I myself did not know how to do that, but fortunately #Grx70 did.. see his answer.
#Eyal Perry is correct with his diagnose of the problem. In order to make it work you should use the FrameworkElement.RegisterName method. Here's an example of how to use it:
DockPanel dock = new DockPanel();
var ruler = new RulerBar { Name = "rulerBar" };
dock.RegisterName(ruler.Name, ruler);
dock.Children.Add(ruler);
dock.Children.Add(new TextControl { RulerBar = "rulerBar" });

Set Background for App.RootFrame from App.Resources in wp8

Friends,
I am assigning the Background of RootFrame to application resources, It works when you explicitly write the Resource name like below
App.RootFrame.Background = (System.Windows.Media.ImageBrush)App.Current.Resources["Theme_6"];
but If I use below it doesn't work:
string themeName = "Theme_6";
App.RootFrame.Background = (System.Windows.Media.ImageBrush)App.Current.Resources[themeName];
Is it possible to use the 2nd options in wp8?
Thanks!
Panorama control (and I think Pivot controls as well) has some problem supporting late binding for background images.
When you hard-code the image paths, there is no problem displaying a static background image.
To assign background images 'on the fly' you should follow these steps;
Create a Property (MainBackGroundImage) within your associated
ViewModel, that implements INotifyPropertyChanged interface (if you
are using MVVM pattern you already have this infrastructure).
Assign any image path (this can be a remote URL as well) to this
property whenever you want to change the background image.
In your View hook up to your ViewModel's property changed event and
update the layout of the control where background image is going to
appear:
void viewModel_PropertyChanged(object sender,PropertyChangedEventArgs e)
{
if (e.PropertyName == “MainBackGroundImage”)
{
this.MainPanorama.UpdateLayout();
}
}
You might perhaps take a look at my open-source WP8 application where I did achieve dynamic background images.

How to generate WPF controls automatically based on XML file?

I have an Xml file which tells me the controls that I have to add to a form but this Xml changes dynamically and I need to update the form.
Currently, I can read the XML file, but I dont know if it is possible to automatically create forms based on that or not ?
Yes It is possible.
WPF offers several ways of creating controls either in Xaml or in code.
For your case if you need to dynamically create your controls, you'll have to create them in code. You can either create your control directly using their constructors as in:
// Create a button.
Button myButton= new Button();
// Set properties.
myButton.Content = "Click Me!";
// Add created button to a previously created container.
myStackPanel.Children.Add(myButton);
Or you could create your controls as a string containing xaml and use a XamlReader to parse the string and create the desired control:
// Create a stringBuilder
StringBuilder sb = new StringBuilder();
// use xaml to declare a button as string containing xaml
sb.Append(#"<Button xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ");
sb.Append(#"Content='Click Me!' />");
// Create a button using a XamlReader
Button myButton = (Button)XamlReader.Parse(sb.ToString());
// Add created button to previously created container.
stackPanel.Children.Add(myButton);
Now for which one of the two methods you want to use really depends on you.
Jean-Louis
You can easily add controls via code in wpf, you can follow this article. Another thing worth noting is that XAML is a form of XML so you can you save your XAML to an XML file, that way you wouldn't need to add controls in code, however it depends on the complexity of your application.
I am pretty new to Xaml but to add to Jean-Louis's answer if you do not want to add the namespaces to every element string then you can do something like this using the System.Windows.Markup namespace:
ParserContext context = new ParserContext();
context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
string xaml = String.Format(#"<ListBoxItem Name='Item{0}' Content='{1}' />", itemID, listItems[itemID]);
UIElement element = (UIElement)XamlReader.Parse(xaml, context);
listBoxElement.Items.Add(element);
Adding controls through the Children.Add method is the quickest way i've found, such as for example
this.Grid.Add(new TextBox() { Text = "Babau" });

Categories

Resources