Can I always replace DynamicResource with a Binding to a Source=StaticResource - c#

What is the difference between A and B both will work.
Can I always replace inplace DynamicResource with a Binding to a StaticResource?
<Button Content="{DynamicResource content}">
<Button.Resources>
<sys:String x:Key="content">A</sys:String>
</Button.Resources>
</Button>
<Button Content="{Binding Source={StaticResource content}}">
<Button.Resources>
<sys:String x:Key="content">B</sys:String>
</Button.Resources>
</Button>
As this doesn't work (because it is defined after it is used):
<Button Content="{StaticResource content}">
<Button.Resources>
<sys:String x:Key="content">C</sys:String>
</Button.Resources>
</Button>

The primary difference between StaticResource and DynamicResource is that a StaticResource only provides a value once, when the Xaml (or Baml) is parsed and applied. Despite what another answer says, a StaticResource is not resolved at compile time.
A DynamicResource provides an expression value, where the expression is a 'live' resource reference that can respond to changes in the future.
For a StaticResource to be applied, the requested resource must be in scope when the markup extension is asked to provide a value. If it's not in scope, the resource lookup will fail. This is not true for a DynamicResource: if the requested resource is not in scope, no value will be applied. If the resource comes into scope later on, it will get picked up. Similarly, if the referenced resource gets removed or replaced, the target property will be updated accordingly.
Because DynamicResource provides an expression for a value, it can only be applied to a dependency property. A StaticResource can be applied to any property that is capable of receiving a markup extension.
With that in mind, let's revisit your question:
Can I always replace [an] in-place DynamicResource with a Binding to a StaticResource?
You can replace a DynamicResource with a StaticResource if and only if:
The resource will be in scope when the Xaml is loaded.
The resource will not be replaced at runtime.
If the above conditions are known to be true, then it's better to use a StaticResource, because static resources are more lightweight than dynamic resources. Using a dynamic resource necessarily requires some additional overhead because change listeners need to be hooked up.
However, it makes little sense to replace {DynamicResource content} with {Binding Source={StaticResource content}}. If all you want to do is insert a resource reference, there is no point in wrapping it a Binding. Just use {StaticResource content}.
There are times when you might want to use a StaticResource for a binding's Source, but it only makes sense if you're drilling down to a value inside the resource, or if you need to apply a converter.
As this doesn't work (because it is defined after it is used):
<Button Content="{StaticResource content}">
<Button.Resources>
<sys:String x:Key="content">C</sys:String>
</Button.Resources>
</Button>
Right. To use a StaticResource directly, you would need to move the resource to an outer scope or set Content after the Resources (using the <Button.Content> element syntax).
Now, about this guy:
<Button Content="{Binding Source={StaticResource content}}">
<Button.Resources>
<sys:String x:Key="content">B</sys:String>
</Button.Resources>
</Button>
Are you sure this works? For me, it works in the designer, but if I actually run the application, it fails just like it does when using StaticResource directly.

DynamicResource is resolved during runtime
while StaticResource is resolved during compile time and placed in the BAML.
If they work then your ResourceDictionaries are resolved correctly.
They both work that's right but they "work" in 2 different ways.
Can I always replace DynamicResource with a Binding to a StaticResource?
You can. Primarily one would use DynamicResource when loading time of the Window or UserControl takes a long time.
EDIT
After your edit I can tell you that the resource that you are trying to use is defined after your attempt to use it. If you move that resource to the top of the Visual Tree i.e. Window or UserControl then it will be available to you. This is because the compiler is trying to resolve the name content which at this point doesn't exists yet. If you would use a DynamicResource which would be resolved during runtime rather than compile time, then you would see the difference.
EDIT 2
As EdPlunket pointed out the StaticResource if changed will not be reflected on the screen, however if you change the DynamicResource then it will be updated.
EDIT 3
I should have probably made this more clear that DynamicResource StaticResource are Markup Extensions that resolve Resources used within the app. Also worth mention that x:Static and x:Type are Markup Extensions` as well.

Related

Cant figure out how to set up up a static resource

I have a grid that I am trying to hook up a visibility converter to. I have a class set up in the HelperObjects namespace, but for some reason the xaml is not picking up the reference. The error message is "The resource BoolToVisConverter could not be resolved" Why won't the xaml pull in this resource? I am sure I am doing something ridiculous here...
Here is the xaml:
xmlns:HelperObjects="clr-namespace:foo.HelperObjects"
...
<Grid Visibility="{Binding isZoneTwoVisible, Converter={StaticResource BoolToVisConverter}}">
The error message is indicating that the resource identified by the key BoolToVisConverter, to which you're trying to bind, cannot be found.
The most likely explanation is that you haven't declared that resource within a scope that can be accessed by your xaml. You'll want to create a StaticResource with a key matching the name you're referencing, within a Resources section of your xaml, the exact location may vary depending on your needs/structure.
Assuming you're doing this within a Window, you could do something like:
<Window>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</Window.Resources>
<Grid Visibility="{Binding isZoneTwoVisible, Converter={StaticResource BoolToVis}}">
<--...Content...-->
</Grid>
</Window>
Note: I haven't included your namespace in front of the BooleanToVisibilityConverter because this is a class which already exists within the framework.
It may be the case you require slightly different behaviour, or don't have access to that class, in which case you may need to add your namespace when defining the resource, e.g. <HelperObjects:BooleanToVisibilityConverter x:Key="BoolToVis"/>
Potentially useful further info about static resources: https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/staticresource-markup-extension
Try to specify the converter in UserControlResources or even parent level Grid Resources. Assuming you are using a UserControl.
And your code is unclear as of where you are defining the StaticResource BoolToVisConverter. But generally heres the process.
Look at this sample code below to define your StaticResorce in the UserControl Resources section. Make sure you set the DataContext where isZoneTwoVisible is residing. I am hoping you implemented ImplementINotifyPropertyChanged and said PropertyChanged on your isZoneTwoVisible or isZoneTwoVisible is a DependencyProperty. Note: BooleanToVisibilityConverter is a class that implements an IValueConverter or if your property is a bool you don't even need that class.
<UserControl.Resources>
<BooleanToVisibilityConverter
x:Key="boolToVisibility"></BooleanToVisibilityConverter>
</UserControl.Resources>
You did all the things said above and it still dosen't work, sometimes I specify the relative Source hoping its residing in a UserControl.
Visibility="{Binding isZoneTwoVisible,Converter={StaticResource boolToVisibility},RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}">

Binding works fine, but intellisense says: Cannot resolve property XXX in data context of type 'object'

I have a binding to a parent-element. How can I provide the data type for the DataContext in the binding, so intellisense can resolve the bound Properties?
The binding works fine at runtime. So, I have the following XAML structure:
<TabControl Name="TabDynamic"
ItemsSource="{Binding TabItems, Mode=OneWay}" ...>
<TabControl.Resources>
<DataTemplate x:Key="TabHeader" DataType="TabItem">
<DockPanel>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Header}" />
<Button Command="{Binding ElementName=TabDynamic, Path=DataContext.DeleteTabCommand}"
CommandParameter="{Binding ElementName=TabDynamic, Path=DataContext.TabItems/}">
<Image Source="{DynamicResource DeleteImg}" Height="11" Width="11"></Image>
</Button>
</DockPanel>
</DataTemplate>
<DataTemplate x:Key="TabContent" DataType="viewModels:ConnectionInfoVM">
<views:BufferViewerControl/>
</DataTemplate>
</TabControl.Resources>
</TabControl>
The data type of the DataContext is "viewModels:ConnectionInfoVM".
Intellisense will now underline both Properties on the DataContext (so DeleteTabCommand and TabItems are underlined).
I already tried to use the design-time data-context definition "d:DataContext" within the Button element like so:
d:DataContext="{d:DesignInstance viewModels:ConnectionInfosVM}"
But this does not change the intellisense warnings.
I also tried to define the DataType on the DataTemplate to be "viewModels:ConnectionInfosVM", as I do for the content-template, but that too does not change the intellisense warnings (and I guess would be wrong, as the data type of the element really is a TabItem).
Another try was to define the DataContext by adding the following to the Button element definition:
<Button.DataContext>
<viewModels:ConnectionInfosVM/>
</Button.DataContext>
But this too, does not get rid of the warnings.
I found a solution at least for the above described problem. I was setting the DataContext of the window in question in the code-behind. The TabControl in my example just inherits that DataContext, which is a ConnectionInfosVM.
In order to fix those warnings (and of course for the gained flexibility in providing a DataContext by a Locator), I defined the DataContext in XAML like so:
<UserControl ...
DataContext="{Binding Source={StaticResource mainViewModelLocator}, Path=ConnectionInfosVM}">
It seems that intellisense is now able to resolve those references. But on the other side, I also changed the TextBlock contained within the DataTemplate to the following:
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=DataContext.Address}" />
Now the DataContext of such a TabItem is actually a different type, as it is the type of the backing object for the TabItem. So in this case, the Property Address cannot be found by intellisense.
So, the question kind of remains, is there a possibility to define the type of the DataContext within a binding defined in a DataTemplate?
I needed to add the mc:Ignorable="d" attribute to the Window tag. Essentially I learned something new. The d: namespace prefix that Expression Blend/Visual Studio designer acknowledges is actually ignored/"commented out" by the real compiler/xaml parser!
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
The following was taken from
Nathan, Adam (2010-06-04). WPF 4 Unleashed (Kindle Locations 1799-1811). Sams. Kindle Edition.
Markup Compatibility
The markup compatibility XML namespace (http://schemas.openxmlformats.org/markup-compatibility/2006, typically used with an mc prefix) contains an Ignorable attribute that instructs XAML processors to ignore all elements/attributes in specified namespaces if they can’t be resolved to their .NET types/members. (The namespace also has a ProcessContent attribute that overrides Ignorable for specific types inside the ignored namespaces.)
Expression Blend takes advantage of this feature to do things like add design-time properties to XAML content that can be ignored at runtime.
mc:Ignorable can be given a space-delimited list of namespaces, and mc:ProcessContent can be given a space-delimited list of elements. When XamlXmlReader encounters ignorable content that can’t be resolved, it doesn’t report any nodes for it. If the ignorable content can be resolved, it will be reported normally. So consumers don’t need to do anything special to handle markup compatibility correctly.

How does binding elementname work exactly?

I remember reading a couple of weeks ago that it sometimes doesn't work inside templates, and I recently tried to bind things in two different windows and it couldn't find the name declarations, so I assumed that it was local to the namespace of the class and just bound by setting the datacontext instead. However, I'm really curious when I am able to use binding elementname and when I cannot, because it's far more convenient when it is possible.
edit: In reading that article, I found this to be interesting:
"For this reason, styles and templates both define their own XAML namescopes, independent of whatever location in an object tree where the style or template is applied."
if this is true, doesn't that mean that Binding ElementName should not work in templates at all? But then I definitely have some working bindings on ElementName within my templates. That is the most confusing part, why do some bindings randomly work inside the templates and others do not? It must have some method for trying to resolve the name even if it isn't in the template or same namescope
Basically you need to be in the same name scope (read this). Most UI elements are in the same tree sharing the same name scope, however there can be breaks and barriers (styles/templates) and if you have abstract objects like DataGrid columns they do not have a name scope at all.
I've been working with WPF long enough to guess when i'll run into problems and i know common areas but don't think there's an easy way to tell in all situations up-front.
if this is true, doesn't that mean that Binding ElementName should not work in templates at all? But then I definitely have some working bindings on ElementName within my templates.
Within is just fine, that is the same scope. The point here is that if you apply the template and they would not have their own scopes there would be conflicts.
e.g.
<Button/>
<Button/>
If we expand the ControlTemplate you would get something like:
<Border Name="bd" Background="{TemplateBinding Background}">...</Border>
<Border Name="bd" Background="{TemplateBinding Background}">...</Border>
Obviously we would get a name conflict.
Same for DataTemplates in ItemsControls, if you name controls in the template that name would conflict with the same control instance in the applied template of other items.
On another note, you can bind from inside a template to the outside because logically there can only be one instance with that name or you can give them a distinct precedence based on how "close" the name scope is, e.g.
<TextBox Name="tb" Text="Test"/>
<ItemsControl ItemsSource="ABC">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text, ElementName=tb}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Do order of code in XAML effect its build relevance in WPF?

I asked a question earlier regarding
<Button Command="{StaticResource hwc}" CommandParameter="Hello" ...
in which to overcome my problem i was asked to switch the place of these two attributes i.e. CommandParameter should come first and Command` later. This way
<Button CommandParameter="Hello" Command="{StaticResource hwc}" ...
No doubt, this thing worked. But left a few questions in my mind.
Do the order of attributes matter?
Does this same principle apply to styles also. My seniors at job say styles should be written/defined in a file before they are used
I have a button designed
<Button Style="{StaticResource FooStyle}" ....
and the style is defined way down below after this button is declared
<Style x:Key="FooStyle" TargetType="{x:Type Path}" ...
Will this style be applied to that button even though it is declared after button is declared?
In code behind we cannot use a variable before its declaration, so does the same apply to XAML code also?
Yes indeed you need to define your Style above its usage if you are referring to it using StaticResource but in case you are referring it as a DynamicResource, the order does not matter. It gets resolved at run time.
<Button Style={DynamicResource FooStyle}...
Refer to this link for detailed description for the difference StaticResource vs DynamicResource

Data Binding Scopes - In Need of clarification

I've been doing some work in WPF, and I for the most part have my bindings working, but I need a scope clarification here. I've run into some seemingly simple operations that require silly binding workarounds and I believe a lot of it has to do with scope.
Example #1 - Out of visual tree, binding to parent.
<ComboBox x:Name="Combo1" ItemsSource="{Binding SomeListOfStrings}">
<ComboBox.ContextMenu>
<ContextMenu>
<MenuItem Header="{Binding ElementName=Combo1, Path=SelectedItem}" />
<MenuItem Header="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=SelectedItem}" />
</ContextMenu>
</ComboBox.ContextMenu>
</ComboBox>
In this example, I'm trying to bind a child-element's property to a parent's property. Since this item isn't in the visual tree under the element, but instead as just a property, I cannot locate the parent using FindAncestor. In my experience I've had no luck binding with ElementName in this case either (Tried both Name="" and x:Name="").
What is the scope here? How does the MenuItem relate to the ComboBox? Because I know it inherits the DataContext of it's parent here, why is it unreachable with FindAncestor / ElementName?
Example #2 - Resources + StaticResource/DynamicResource
<UserControl x:Name="MainControl" ... />
<UserControl.Resources>
<Style TargetType="ComboBox">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu ItemsSource="{Binding ViewModelsMenuItems}" />
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ComboBox" x:Key="Example2_Style2">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu ItemsSource="{Binding ElementName=MainControl, Path=DataContext.ViewModelMenuItems}" />
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<StackPanel>
<ComboBox />
<ComboBox />
<ComboBox Style="{StaticResource Example2_Style2" />
</StackPanel>
</UserControl>
In this example, I'm trying to set the context menu for all ComboBox's in my user control (or specific ones if I used a named style). Since the ContextMenu is defined outside of scope, and "set" into scope, I've experienced issues before with the DataContext being inherited, Or being able to use ElementName (Because the item is out of scope?).
Bonus Question
Since I've had terrible luck alltogether with ElementName can someone please tell me which to use, because I see both ALL OVER the internet/books. Name="Whatever" or x:Name="Whatever"
Update (As per request)
The type of binding failures I am getting are:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ComboBox', AncestorLevel='1''. BindingExpression:Path=SelectedItem; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Header' (type 'object')
There is something called inheritance context on which there is not all too much information to be found except this blog post (archive).
In that article the ContextMenu is given as an example where no linking occurs.
I for one would solve this issue using the PlacementTarget property:
<ContextMenu>
<MenuItem Header="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
</ContextMenu>
Original article has dissapeared; here are the main points from an archive:
Nick on Silverlight and WPF
What’s an inheritance context?
Nick Kramer [MSFT] August 17, 2006
But before I tell you about inheritance contexts, I have to explain
the problem it solves. Once upon a time, property inheritance looked
only at the logical tree and the visual tree -- so if an element
didn't have a logical or visual parent, its properties didn't inherit
values from the parent it didn't have. Which makes sense if you think
about the world in terms of code. But if you look at the world
through xaml glasses, there's a lot of places where one element looks
like it has a parent when it really doesn't. Consider the following:
<Button>
<Button.Background>
<SolidColorBrush>green</SolidColorBrush>
</Button.Background>
</Button>
Quick, what's the parent of SolidColorBrush? If you said Button, you
would be wrong -- SolidColorBrush is not part of the visual tree (it's
not a Visual). Nor is SolidColorBrush part of the logical tree,
because if you call Button.Content the answer is not the
SolidColorBrush. So SolidColorBrush in this example has no parent, so
it didn't inherit property values from anyone.
At first this may seem academic -- who cares if SolidColorBrush
inherits? Actually, there's a couple reasons it matters, the
DataContext property and the Loaded event. DataContext is an
inherited property that use the default data source for your {Binding}
statements. When you write:
<SolidColorBrush Color="{Binding}"/>
Since you didn't specify a data source (and who does), it uses the
DataContext property. And if that inherits the way you expect,
everything is happy. But it's easy to write:
<Button DataContext="whatever">
<Button.Background>
<SolidColorBrush Color="{Binding}"/>
</Button.Background>
</Button>
And be confused that your SolidColorBrush didn't inherit the
DataContext. Similarly, the Loaded event was originally tied to the
logical tree, so if you put your MediaElement inside a VisualBrush,
there would be a gap in the visual tree and your media would never get
a Loaded event and never start play the video.
And that's why we invented inheritance context. You can think of it
as logical tree 2.0 -- inheritance context is an extra pointer, which
the property engine uses when there's no logical parent or visual
parent to get values from. Inheritance context don't solve every
problem in this space, but they solve a lot of them, and in the future
we'll add more inheritance context pointers and solve more problems.
There's a number of places we establish inheritance context pointers,
I won't try to list all of them but here are some of the more
interesting ones:
Freezable inside a FrameworkElement -- our SolidColorBrush/Button
sample above FrameworkElement inside a VisualBrush Triggers and
setters
Resource dictionaries present another interesting case. Suppose you
use DynamicResource inside a resource dictionary:
Does that dynamic resource get evaluated where the SolidColorBrush was
defined? Or where the brush gets used? If the latter, what happens
if you use the SolidColorBrush in two different places where the
DynamicResource will give two different answers? It may sound
contrived:
<Window.Resources>
`<Color x:Key="color">red</Color>`
`<SolidColorBrush x:Key="brush" Color="{DynamicResource color}" /> `
</Window.Resources>
<Button>
<Button.Background>
<StaticResource ResourceKey="brush"/>
</Button.Background>
</Button>
<Button>
<Button.Resources>
<Color x:Key="color">blue</Color>
</Button.Resources>
<Button.Background>
<StaticResource ResourceKey="brush"/>
</Button.Background>
</Button>
But it actually happens in real code. We chose the first solution,
the inheritance context for SolidColorBrush points to the resource
dictionary, and not its point of use.
Inheritance context has been wonderfully useful, but we haven't put
inheritance context links everywhere that's theoretically possible,
mostly because of time in the day (adding inheritance context links
are very difficult to implement performantly and without causing
undesired behavior changes). Probably the simplest example of where
we don't have inheritance context links is across random property
elements:
<Button>
<Button.ContextMenu>
<ContextMenu/>
</Button.ContextMenu>
</Button>
ContextMenu is neither a visual nor logical child of Button, nor is it
one of the inheritance context cases listed above (ContextMenu is not
a Freezable). But, with inheritance context concept at our disposal,
we hope to solve that in future versions of WPF.

Categories

Resources