My WPF project consists of many Pages that all load into the same frame. I currently specify d:DesignHeight and d:DesignWidth in the Page tag in each individual file. I would like to just specify it in one place if possible (like a Style).
I tried setting it as a Style in my App.xaml.
<Style x:Key="PageStyle" TargetType="{x:Type Page}">
<Setter Property="d:DesignHeight" Value="942" />
<Setter Property="d:DesignWidth" Value="1264" />
The Pages render correctly in the designer, but the code fails to build:
Error: Cannot find the Style Property 'DesignHeight' on the type 'System.Windows.Controls.Page'
How can I set the same d:DesignHeight and d:DesignWidth for several pages in one place?
I'm afraid you can't. The designer properties are not real properties--they are directives that get ignored by the Xaml parser.
In fact, you can only use them when you explicitly tell the parser to ignore them:
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
The mc:Ignorable directive tells the parser to ignore any lookup failures that occur within the given namespaces. If you attempt to reference one of the designer properties without adding the designer namespace to mc:Ignorable, you will get a compile-time error:
The property 'DesignWidth' does not exist in XML namespace 'http://schemas.microsoft.com/expression/blend/2008'.
As these are not real properties, you cannot apply them with a Setter, nor can you set them programmatically. Sorry.
Addendum
I spent some time investigating other options for setting the width and height in design mode. I tried custom attached properties, subclassing Page, and even overriding the default metadata for Width and Height in design mode. Invariably, I could get each approach working for almost any control except Window and Page. I suspect this is because of the way the designer displays windows and pages using special proxy elements.
At this point, I am reasonably confident there is no way to make this work with the VS 2017 Xaml designer.
Related
I have a need to display a certain WPF control only in the [VS 2017] designer, but not during run time. (Specifically, a background image to lay out the components).
As I learned, the opposite effect (hiding a control at design time) can be achieved using the undocumented d:IsHidden="true" attribute, from the namespaces that are typically included even by default:
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
There is another feature to have a design-time style with d:DesignStyle.
But I couldn't find anything like d:Visible or something to the effect.
So, are there any simple methods to have a design-time-only component, similar to having a special 'd' attribute? I'd prefer not to use a custom code-behind, because there is at least a trivial (but annoying) solution: just comment out the component before compilation!
Ideally, the whole component should be disabled/removed at run time, so that it didn't take any resources.
More generally, is there a way to find all these 'undocumented' features of the d namespace?
You could just put this in your Window or UserControl constructor after the InitializeComponent() call:
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
myDesignControl.Visibility = Visibility.Collapsed;
}
Doing this also allows the ability to turn the control back on again at runtime, which I often find useful for debugging tools or diagnostics.
'd' is not magical nor anything official. It is an alias for an xml namespace that is local to to xaml/XML file where it is defined.
This line defines d in the code in the question:
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
So to find information about 'features' of this namespace there should be a list of all classes that are in this namespace. Most of them are in the Microsoft Expression Blend SDK: https://www.microsoft.com/en-us/download/details.aspx?id=22829
Providing design-time data for DataContext is easy with use of d:DataContext but what about control properties referenced with {TemplateBinding} or {RelativeSource TemplatedParent} from Style.Template ?
Should I just populate control with sample data inside constructor/Loaded event when DesignerProperties.GetIsInDesignMode(this) returns true ?
(Can't do this since it would break normal design experience).
What about third party-controls that I can't modify ?
For my own controls I usually do something like:
<Style x:Key="FooStyle>
<Setter Property="Template>
<Setter.Value>
<ControlTemplate TargetType="FooControl">
<Grid d:DataContext="{d:DesignInstance FooDesignTimeData, IsDesignTimeCreatable=True}">
... guts of control template go here ...
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Where "FooDesignTimeData" is a class that provides design time data in the appropriate form (implementing the interface from your runtime view model is a good practice here).
I don't see why this wouldn't work for a 3rd party control as well. You might not even have to retemplate the control -- you might be able to get away by just specifying the 3rd party control inside of your style and giving it a design time data context as specified above, but I haven't tried that scenario. I assume you're going to all this trouble because you're forced to use a control that does not have a great design time experience (such as by providing a Vendor.Controls.Design.dll or Vendor.Controls.Expression.Design.dll file).
To work with the TemplateBindings, I don't have a great solution. Usually I create a test page that displays my control and allows me to switch templates around. During integration you'll have an extra view (either within your app or as a separate app) that allows you to create and manipulate instances of the control as necessary. The GoToStateAction targeted trigger action from the Blend SDK is often useful here. For example, create a button for each visual state and then use the Click even to trigger a transition to a particular state. Thus you can easily test all of your states plus transitions while bound to test data. Hacky and not really design time data, but it works.
What's the best way to enable dynamic skinning of a WPF Application when some items requiring skin modification do not support values of type DynamicResourceExtention? In particular, our problem is that ConverterParameters require StaticResourceExtentions.
Here's our situation with ConverterParameters Using Visual Studio 2008 and WPF 3.5.
We have a custom converter which takes a value and a parameter and simply returns their product.
Very simple, works fine, and we use it for various tasks, including setting some window element sizes. For example, passing a value of "Source={x:Static SystemParameters.PrimaryScreenHeight}" and a parameter of "0.1" enables us to set an element's height to exactly 1/10 of the screen height.
Height="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight},
Converter={StaticResource PctConverter},
ConverterParameter=0.1}"
where PctConverter is a resource reference to our custom converter. No problem there.
Now we want to skin the application dynamically, by extracting the ConverterParameter and putting it in a seperate resource. For example, we might want the element height to be 0.1 of the screen height in some skins, and say 0.25 of the screen height in others. Initially we thought we'd simply set the ConverterParameter to a DynamicResource, but this is not supported, so we have to set it using a StaticResourceExtension like this:
Height="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight},
Converter={StaticResource PctConverter},
ConverterParameter={StaticResource OurElementHeightParameter}}"
where OurElementHeightParameter is defined in a seperate ResourceDictionary (call it MainResource.xaml) as follows:
<sys:Double x:Key="OurElementHeightParameter">0.1</sys:Double>
(where namespace is defined as xmlns:sys="clr-namespace:System;assembly=mscorlib".)
This works fine, as far as extracting the CustomParameter is concerned, but it still hasn't enabled us to change our ConverterParameter by swapping skins on the fly.
After researching this some more, in particular the following articles
How to assign wpf resources to other resource tags
Skinning using a color as staticresource for another color
Aliasing resources
what we think we need to do now is take our StaticResourceExtention and set its value dynamically behind the scenes using resource aliases.
Trying to do this, we replaced the previous OurElementHeightParameter resource with the following two resources
<sys:Double x:Key="SkinnedHeightRatio">0.1</sys:Double>
<StaticResourceExtension x:Key="OurElementHeightParameter" ResourceKey="SkinnedHeightRatio" />
which works fine, producing an identical result.
When that worked okay, we thought it would be a simple matter of placing the SkinnedHeightRatio resource in a seperate ResourceDictionary (call it Skin.xaml) and merging that with the original MainResource.xaml ResourceDictionary and we would have the dynamic skinning we are after.
But, as soon as we extract <sys:Single x:Key="SkinnedHeightRatio">0.1</sys:Single> to another ResourceDictionary we encounter build error as follows:
Unknown build error, 'Index was out of range. Must be non-negative and less than the size of the collection.'
Even more strange is that if we keep the two resources above in the same ResourceDictionary and just seperate them by putting another random resource between them, for example
<sys:Double x:Key="SkinnedHeightRatio">0.1</sys:Double>
<Thickness x:Key="SomeRandomResource" >5</Thickness>
<StaticResourceExtension x:Key="OurElementHeightParameter" ResourceKey="SkinnedHeightRatio" />
then the OurElementHeightParameter points to the SomeRandomResource directly above it and not the
resource specified in its ResourceKey property (SkinnedHeightRatio) which is only 2 lines above it...
In this case, the parameter passed to the converter is the Thickness SomeRandomResource.
All very confusing, and makes us think we are barking up the wrong tree completely. So where are we going wrong?
If anyone needs full code for an application reproducing the problem, I can post it up.
Any pointers greatly appreciated.
It might be simpler to create a multi-value converter and bind to two values for it.
EDIT: I was able to reproduce this in a very stripped-down version of the application. Here is a link to the .zip file
http://www.mediafire.com/?cn918gi15uph1xe
I have the module add the view to two different regions - the status bar region along the top is where the issue occurs. The weird part is, when the same view type is added to the main region, there are no problems. The status bar region is an ItemsControl and the main region is a ContentPresenter. That is the only difference.
Please let me know if you have any insight! Thanks.
-----Original Post-----
Hello all,
I am seeing some weird behavior with WPF. I'm using .NET 4 and PRISM v4. The way we have our application structured is that the skin resource dictionaries exist in their own assembly. The modules do not reference this assembly - instead we have a skin manager class that reads from a config file which skin we want and loads the appropriate components into a merged dictionary. The merged dictionary is set in the Application resources (we clear out the Application.Resources.MergedDictionaries before we add it). The idea is that we can later switch skins at runtime if needed, and the modules don't need to know about the skins until runtime.
Then in our xaml we are referencing styles using DynamicResource. The problem has to do with a TextBlock style defined in the skin and referenced by key, such as
<TextBlock Style="{DynamicResource someKey}" ... />
The style defines the font family, font size, and foreground. The font family and size are applied correctly (I verified this). The foreground, however, is always black. I used Snoop and WPF Inspector to see that the foreground value is "inherited" instead of coming from the style.
I also have a control that inherits from TextBlock and all it does is add some properties that determine what the text value should be (it doesn't affect the style at all). I was able to add a property changed override for the Foreground property and found out that the style's foreground value gets applied, and then the inherited value gets applied after that. I wasn't able to get the .NET source debugging to work so I couldn't figure out why/where it was being called from the second time...
Here is a link to an old, old post from a guy with the exact same problem - he did not find the answer, but instead a workaround. Unfortunately the workaround only works on the inherited control (I can't set InheritanceBehavior for TextBlocks).
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/3501ed19-ab40-4064-81b5-e9b7b9d35b56
My guess is that for TextBlock the foreground property is inherited from its parent unless you explicitly set it on your TextBlock instane. For example if you change the Window or UserControl that this Textblock is in to have a Foreground of blue does it work? One thing you can try doing is in the style instead of setting just Foreground to a color, set TextElement.Foreground. See if that works.
It doesn't explain why the problem exists, but a fix was found here:
http://compositewpf.codeplex.com/discussions/257596
The fix is to load the skins before creating/adding views to the shell.
I have a WPF UserControl with binding converters referenced like this:
<UserControl x:Class="MyControl" x:Name="MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TheMainNamespaceOfThisAssembly">
<UserControl.Resources>
<local:ConfidenceColorConverter x:Key="ConfidenceColorConverter"/>
</UserControl.Resources>
I then use the binding converter later. I see the user control in my design window. Then I compile, then place this user control in my main window. I run it and it works. However, I still would like to use the designer on the main window, which breaks with:
Could not create an instance of type 'MyControl'.
So I learned how to debug the designer; when I do, I get an XamlParseException:
Cannot find type 'TheMainNamespaceOfThisAssembly.ConfidenceColorConverter'. The assembly used when compiling might be different than that used when loading and the type is missing. Error in markup file...
If remove the references to the converters, my user control displays well in the designer on the main window. Any ideas how to fix my references to the converters so that they won't break the designer?
Couldn't understand if the article Troubleshooting WPF Designer Load Failures applies or not.
Could you please try to reproduce the problem on a clean new project rather than editing your existing one? You cannot have
<UserControl x:Class="MyControl" x:Name="MyControl"...
as you would need to add a namespace to "x:class" and change "x:Name" value to be different from class name. The designer works fine when I create a clean project as you describe and fix this sort of errors. You might be omitting some details from the question you think are unimportant, but those details can make all the difference.
After talking with others, the VS2008 designer has numerous problems that prevent its use in many situations. We gave up.
Update: It seems like some, especially Joel Cochran, are using the Expression Blend design view with more success, as long as you obey his four principles of MVVM in XAML development.