Can you programmatically set a property in a ControlTemplate from a ChildWindow? - silverlight

I am working on a Silverlight application that has resource files that define styles for the different types of Child Windows in the application. The <Style> contains <ControlTemplate> markup with various content. Is there a way to set one of the properties of the controls defined within the <ControlTemplate> from the Child Window's class?
For example, imagine in the resource file I have markup like the following:
<Style x:Key="MyChildWindowStyle" TargetType="sdk:ChildWindow">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="sdk:ChildWindow">
<Grid x:Name="Root">
...
<Image Source="/Assets/image.png" />
...
</Grid>
</ContentTemplate>
</Setter>
</Style>
Now assume that I have a number of child windows that are configured to use this style. What I'd like to be able to do is from the code in those child windows be able to programmatically change the value of the image's Source.
Is this possible?
Thanks

In your resources you can do this:
<BitmapImage x:Key="MyImage" Source="/Assets/image.png"/>
<Style x:Key="MyChildWindowStyle" TargetType="sdk:ChildWindow">
...
<Image Source="{DynamicResource MyImage}" />
...
</Style>
Then in your child window's code-behind you can do this:
Resources["MyImage"] = new BitmapImage(new Uri("/Assets/other-image.png"));
But if your child window class is in another assembly you should be writing the uri a bit different:
Resources["MyImage"] = new BitmapImage(new Uri("pack://application:,,,/MyOtherAssemblyShortName;component/Assets/other-image.png"));
You can check msdn page for package uri format.
But I suggest you to use MVVM pattern in order to get most out of WPF in terms of bindings, styling etc. When you have a view model instead of a code-behind these things become simpler. You may wanna check the related msdn page, a codeproject sample, a toolkit or a validation mechanism designed for MVVM.

#zahir's answer pointed me in the right direction, but to get it to work in Silverlight I had to do the following:
First, I added the <BitmapImage> markup to my resource file, using the UriSource property to specify the default value.
<BitmapImage x:Key="MyImage" UriSource="../Assets/DefaultImage.png" />
Next, I referenced it in the <ControlTemplate> like so:
<Image ... Source="{StaticResource MyImage}"/>
Then, in my code-behind class I was able to modify the UriSource property like so:
BitmapImage img = (Application.Current.Resources["MyImage"] as BitmapImage);
if (img != null)
img.UriSource = "../Assets/NewImage.png";
Of course, the precise values for UriSource would depend on how you are handling image assets, where they are located, etc.

Related

WPF style in Application resources

I have a style in application resources which I want to apply to many different pie charts. The style looks like this:
<Style x:Key="aaa" TargetType="{x:Type nm:CustomChartControl}">
<Setter Property="..." Value="..." />
<!-- etc -->
<nm:CustomChartControl.Series>
<nm:PieSeries /> <!-- PROBLEM -->
</nm:CustomChartControl.Series>
</Style>
There is a lot more properties which I exluded for simplicity. This all works well. Now, some of my pies need to have a different "model" for paitning background for a slice (ex dashed), and this is were the problem occurs.
When I set a model (at runtime) for nm:PieSeries in a particular chart, then this model is also applied to all other pies that are shown in application. As if there is only one instance of that is used by all pies that applied the style.
Is there some way I can tell it to create a new instance of nm:PieSeries each time a Style is applied to new control?
You might try creating the PieSeries as a separate, non-shared resource:
<nm:PieSeries x:Shared="False" x:Key="NonSharedPieSeries" />
And then use that resource in the style:
Value="{Binding Source={StaticResource NonSharedPieSeries}}"
(...and thanks OP for correcting my error in how to bind it to Value).

Apply default Button style to custom Button class

I've created a custom IconButton class that inherits from Button and adds a few dependency properties to place an image in front of the button's text.
The code begins like this:
public partial class IconButton : Button
{
// Dependency properties and other methods
}
It comes with a XAML file that looks like this:
<Button x:Class="Unclassified.UI.IconButton" x:Name="_this" ...>
<Button.Template>
<ControlTemplate>
<Button
Padding="{TemplateBinding Padding}"
Style="{TemplateBinding Style}"
Focusable="{TemplateBinding Focusable}"
Command="{TemplateBinding Button.Command}">
<StackPanel ...>
<Image .../>
<ContentPresenter
Visibility="{Binding ContentVisibility, ElementName=_this}"
RecognizesAccessKey="True"
Content="{Binding Content, ElementName=_this}">
<ContentPresenter.Style>
...
</ContentPresenter.Style>
</ContentPresenter>
</StackPanel>
</Button>
</ControlTemplate>
</Button.Template>
</Button>
That works well so far. (But if you know a simpler way to override a Button's content without changing the entire template and placing a Button within the Button, please let me know. Every time I tried, Visual Studio 2010 SP1 immediately crashed the moment I closed the final XML tag.)
Now I've added some code to fix WPF's broken Aero2 theme for Windows 8. It's a separate ResourceDictionary that overwrites all sorts of default styles: (Based on this, via here)
<ResourceDictionary ...>
<Style TargetType="{x:Type Button}">
...
</Style>
</ResourceDictionary>
The new ResourceDictionary is added to the Application Resources on startup, in App.xaml.cs:
protected override void OnStartup(StartupEventArgs args)
{
base.OnStartup(e);
// Fix WPF's dumb Aero2 theme if we're on Windows 8 or newer
if (OSInfo.IsWindows8OrNewer)
{
Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Resources/RealWindows8.xaml", UriKind.RelativeOrAbsolute)
});
}
...
}
This also works well for normal Button controls I place in my XAML views. (I'm still looking for a method to find out the real Windows theme instead of relying on the version number.)
But my IconButton control doesn't consider these new defaults and is still based on WPF's built-in Button style which is very basic. (It's really just a tight rectangle without all the details and interactivity that Win32 shows.)
I guess I need a way to tell my IconButton that it should re-evaluate the base style and see the newly added RealWindows8 styles. How can I do that?
I found the solution. There are two ways to accomplish this. Either one is sufficient.
The XAML way:
Add the Style attribute to the derived control. This presets the new control's style explicitly to whatever has been defined in the application as the Button style. StaticResource is sufficient for this. If a different Style is specified where the derived control is used, that will replace this initial value.
<Button Style="{StaticResource {x:Type Button}}" ...>
...
</Button>
The code(-behind) way:
Call the SetResourceReference method in the constructor of the derived class.
public IconButton()
{
// Use the same style as Button, also when it is overwritten by the application.
SetResourceReference(StyleProperty, typeof(Button));
...
}
I've tested this for my IconButton as well as a derived TabControl and TabItem class.
(Source)

Convert System.Drawing.Image resource into System.Windows.Controls.Image for wpf MenuItem

I've got resources in my assembly which I can Access using Properties.Resources.MyImage.
And I have some class which I bind to a WPF MenuItem containing a property
public System.Windows.Controls.Image Icon {get; set;}
This I want to set programmatically using:
dummy.Icon = Properties.Resources.MyImage;
Now I want to convert the resource System.Drawing.Image to the WPF System.Windows.Controls.Image. I thought this should be straightforward, but I found no working solution for my Images (which are png files using transparency).
So how do I convert System.Drawing.Image into System.Windows.Controls.Image?
Instead of using Properties.Resources, which are Windows Forms Embedded Resources, use WPF resources. In Solution Explorer, click the image file and in the properties window, set its Build Action to Resource (not Embedded Resource). This also embeds the image into the assembly, but in a different way.
Unlike Windows Forms, WPF does not generate a resource manager class, so you'd have to use strings to load the images dynamically:
BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri("pack://application:,,,/NameOfAssembly;component/Path/To/Image.png");
image.EndInit();
Note the application and component parts of the URI are constant strings, while NameOfAssemly is the name of the assembly where the image is in. You can build a helper class that builds the URI and loads images.
You can also call image.Freeze() if you don't plan on making any changes to the image (improves performance and allows image source to be created on non-UI threads).
In your data class, expose an ImageSource property instead of an Image. Then you use the Image control to display it:
<Image Source="{Binding Icon}" />
Or inside a style:
<Style TargetType="MenuItem">
<Style.Resources>
<Image x:Key="Icon"
x:Shared="False"
Source="{Binding Icon}"
Width="16"
Height="16" />
</Style.Resources>
<Setter Property="Icon" Value="{StaticResource Icon}" />
</Style>

What is the Equivalent of SetResourceReference in a Metro Application?

I'm attempting to set a reference to a style in a control I'm creating in the code behind. Normally in WPF, I'd use the SetResourceReference method. However, I see that this method doesn't seem to exist on the Button property in Metro.
What is the equivalent in a Metro application?
WinRT, like Silverlight, doesn't have that technique (it's missing "DynamicResource" markup extension and the support that goes with it).
You could try one of the following:
Set the style property
Set the template property
To set the Style for example, you can do something like this.
With Resources:
<Page.Resources>
<Style TargetType="Button" x:Key="boldButton">
<Setter Property="FontWeight" Value="Bold" />
</Style>
</Page.Resources>
and a button:
<Button Name="btn" Content="Button" />
In the code behind:
btn.Style = this.Resources["boldButton"] as Style;
I ended using a custom implementation of TryFindResource shown here. The problem with using the this.Resources property suggested in a different answer is that it doesn't search up the entire resource tree for resources that might be in the App resources. The implementation in the link I provided does that. It is based off of something common in Silverlight which has the same issue.

how to reference current control in grid?

I want to creat my own control:
public class DataGrid : System.Windows.Controls.DataGrid
In the style definition, I want to add a button above the grid, so I wrote:
<Style TargetType="local:DataGrid">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:DataGrid">
<Grid>
<Button Content="Addnew"></Button>
<?????>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But how can I tell the xaml to put the grid at postion ????? ?
Thank you all!!
Are you sure that you want to use inheritance here? You should consider creating another control that contains a DataGrid rather than inheriting from DataGrid and use the default Template.
If you decide that you do need to customize the Template of the DataGrid you will need to recreate the entire DataGrid template. You can find the original DataGrid template by opening the DataGrid's assembly in .net reflector or a similar application and opening the embedded resource "generic.xaml". This file will contain a ResourceDictionary defining all the default styles for the Controls defined in the assembly. You can copy the default Template from here and modify it as necessary.
Alternatively, if you have Expression Blend you can have it do this automatically by right clicking on the DataGrid control and choosing "edit a copy of this template" (or something like that, I can't remember the exact wording off the top of my head).

Resources