I've got a somewhat special problem: I have a markup extension that needs to check an attached property. The attached property is defined as inheritable.
This works properly in XAML for all elements that are defined under a Window/UserControl, but not for resources. For example, given this XAML:
<Window MyAttachedProp="...">
<Window.Resources>
<FlowDocument x:Key="Doc">
<Paragraph><Run Text="{MyMarkupExtension}" /></Paragraph>
</FlowDocument>
</Window.Resources>
<FlowDocumentScrollViewer Document="{StaticResource Doc}" />
...
</Window>
The markup extension fails because when the ProvideValue()-function is called, the attached property is not derived from the Window to the FlowDocument and to the Run.
Is there same workaround to make this work?
Thanks,
Steven
From Inheriting Property Values Across Tree Boundaries:
Property inheritance works by traversing a tree of elements. This tree
is often parallel to the logical tree
Apparently a resource dictionary does not constitute an element tree and hence the value won't be inherited. However, i guess it should work when you set the property on the FlowDocument, since that is the root of an element tree:
<Window.Resources>
<FlowDocument x:Key="Doc" MyAttachedProp="...">
<Paragraph><Run Text="{MyMarkupExtension}" /></Paragraph>
</FlowDocument>
</Window.Resources>
Related
I'm trying to add some resources to my MainWindow.xaml file but I cant seem to open the tag Window.Resources due to ambiguous reference error.
This hints to me that I have some assembly that also has the name Resources, but that is not the case, I don't have any folders/classes with that name. What could be causing that? Or rather what are the other "references" causing the compiler to be unsure which one to select?
Window.Resources is an example of the special property element syntax that can be used in XAML.
Specifically, the syntax begins with a left angle bracket (<),
followed immediately by the type name of the class or structure that
the property element syntax is contained within. This is followed
immediately by a single dot (.), then by the name of a property, then
by a right angle bracket (>). As with attribute syntax, that property
must exist within the declared public members of the specified type.
I've emphasized the important point that causes the error.
What you're currently doing, is trying to assign something to a property Resources in a type Window but in an instance of a Grid.
So you should either place your resources in the Window instance like this:
<Window>
<Window.Resources>
<!--your resources here-->
</Window.Resources>
<Grid>
<!--your grid content here-->
</Grid>
</Window>
...or you should place your resources in the Grid:
<Window>
<Grid>
<Grid.Resources>
<!--your resources here-->
</Grid.Resources>
<!--your grid content here-->
</Grid>
</Window>
Sorry, I'm thrashing around a bit learning MVVM, WPF, and XAML simultaneously.
I have a problem that I created and I am completely confused with how this should be handled in MVVM.
What I have is a parent window that contains a user control that draws graphs. The graph drawing XAML used to be part of the parent window, but I moved it to a user control for organization as the parent window was very big.
In the parent windows XAML I have .....
<Window ....>
<Window.Resources>
<ViewModel:DropGraphViewModel x:Key="myViewModel"/>
</Window.Resources>
<!-- Set the data context to the view model. -->
<Window.DataContext>
<Binding Source="{StaticResource myViewModel}"/>
</Window.DataContext>
.....
</Window>
And then in the new user control XAML class I have a resource that is created that is a 'generator' class that serves up things that will be used by parts of the graph. It looks like this...
<UserControl ......
<!-- Graph resources -->
<Grid.Resources>
<!-- The binding here for ItemsSource represents the collection the graph will be bound to -->
<!-- THIS LINE DOESN'T WORK ANYMORE -->
<Graphs:LineChartGenerator x:Key="generator" ItemsSource="{Binding Source={StaticResource myViewModel}, Path=SampleData}" Width="500" Height="200"> -->
</Grid.Resources>
And then later on when I want to do some things like draw graph lines I used to reference the generator through binding.
<!-- Connect the points -->
<Polyline Points="{Binding Source={StaticResource generator}, Path=Points}" Stroke="Blue" />
What is now broken now that I am in am using a nested user control is that when I create the instance of the 'generator' class in the resources, I can't pass in the binding that was ItemsSource="{Binding Source={StaticResource myViewModel}, Path=SampleData}" because I no longer have access to the view model (myViewModel) that is in the static resource of the parent window! So I can't set the binding during the creation time of the resource like I used to do.
What is the proper MVVM way to handle this type of pattern?
How do I inject the ItemsSource into my new user control so that it can pass it in when it creates the LineChartGenerator class instance?
DataContext is an inheritable DependencyProperty which means it trickles down the visual hierarchy.
Resources are not part of visual tree until they are hosted.
So in your case, your Graphs:LineChartGenerator has to be hosted in your UserControl and not delcared in the Resource section. Once you do that it acquires its own DataContext from the parent Window, this way as #GazTheDestroyer, pointed out you only need a implicit binding ItemsSource="{Binding SampleData}"
Since you are setting your ViewModel to be the DataContext of the outer Window, it will also be the DataContext of your UserControl, so you should be able to access it with a simple:
<Graphs:LineChartGenerator x:Key="generator" ItemsSource="{Binding SampleData}" Width="500" Height="200">
In the above image, child is a ContentPresenter. Its Content is a ViewModel. However, its ContentTemplate is null.
In my XAML, I have a TabControl with the following structure:
<local:SuperTabControlEx DataContext="{Binding WorkSpaceListViewModel}"
x:Name="superTabControl1" CloseButtonVisibility="Visible" TabStyle="OneNote2007" ClipToBounds="False" ContentInnerBorderBrush="Red" FontSize="24" >
<local:SuperTabControlEx.ItemsSource>
<Binding Path="WorkSpaceViewModels" />
</local:SuperTabControlEx.ItemsSource>
<TabControl.Template>
<ControlTemplate
TargetType="TabControl">
<DockPanel>
<TabPanel
DockPanel.Dock="Top"
IsItemsHost="True" />
<Grid
DockPanel.Dock="Bottom"
x:Name="PART_ItemsHolder" />
</DockPanel>
<!-- no content presenter -->
</ControlTemplate>
</TabControl.Template>
<TabControl.Resources>
<DataTemplate DataType="{x:Type vm:WorkSpaceViewModel}">
....
WorkSpaceViewModels is an ObservableCollection of WorkSpaceViewModel. This code uses the code and technique from Keeping the WPF Tab Control from destroying its children.
The correct DataTemplate - shown above in the TabControl.Resource - appears to be rendering my ViewModel for two Tabs.
However, my basic question is, how is my view getting hooked up to my WorkSpaceViewModel, yet, the ContentTemplate on the ContentPresenter is null? My requirement is to access a visual component from the ViewModel because a setting for the view is becoming unbound from its property in the ViewModel upon certain user actions, and I need to rebind it.
The DataTemplate is "implicitly" defined. The ContentPresenter will first use it's ContentTemplate/Selector, if any is defined. If not, then it will search for a DataTemplate resource without an explicit x:Key and whose DataType matches the type of it's Content.
This is discussed here and here.
The View Model shouldn't really know about it's associated View. It sounds like there is something wrong with your Bindings, as in general you should not have to "rebind" them. Either way, an attached behavior would be a good way to accomplish that.
I think the full answer to this question entails DrWPF's full series ItemsControl: A to Z. However, I believe the gist lies in where the visual elements get stored when a DataTemplate is "inflated" to display the data item it has been linked to by the framework.
In the section Introduction to Control Templates of "ItemsControl: 'L' is for Lookless", DrWPF explains that "We’ve already learned that a DataTemplate is used to declare the visual representation of a data item that appears within an application’s logical tree. In ‘P’ is for Panel, we learned that an ItemsPanelTemplate is used to declare the items host used within an ItemsControl."
For my issue, I still have not successfully navigated the visual tree in order to get a reference to my splitter item. This is my best attempt so far:
// w1 is a Window
SuperTabControlEx stc = w1.FindName("superTabControl1") as SuperTabControlEx;
//SuperTabItem sti = (SuperTabItem)(stc.ItemContainerGenerator.ContainerFromItem(stc.Items.CurrentItem));
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(stc);
//ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(sti);
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
The above code is an attempt to implement the techniques shown on the msdn web site. However, when I apply it to my code, everything looks good, except myDataTemplate comes back null. As you can see, I attempted the same technique on SuperTabControlEx and SuperTabItem, derived from TabControl and TabItem, respectively. As described in my original post, and evident in the XAML snippet, the SuperTabControlEx also implements code from Keeping the WPF Tab Control from destroying its children.
At this point, perhaps more than anything else, I think this is an exercise in navigating the Visual Tree. I am going to modify the title of the question to reflect my new conceptions of the issue.
Having {Binding ElementName=foo}, will it lookup visual or logical tree?
Of logical and visual trees in WPF | Data See, Data Do
When does the logical tree matter?
When looking up a name, such as in
{Binding ElementName=Foo}, the search
walks up the ancestry looking for a
name scope, again just as it does for
inheritable properties.
ElementName binding in Silverlight via Attached Behaviours
In order to enable this, WPF provides
ElementName and RelativeSource
bindings, giving you a powerful
mechanism for locating other elements
within your visual tree to bind to
EDIT:
It looks like the Logical Tree used for binding by ElementName.
Argument # 1.
According to MSDN article FrameworkElement Class:
FrameworkElement extends UIElement
and adds the following capabilities:
Support for data binding and
dynamic resource references: The
property-level support for data
binding and resources is implemented
by the DependencyProperty class and
embodied in the property system, but
the ability to resolve a member value
that is stored as an Expression (the
programming construct that underlies
both data binding and dynamic
resources) is implemented by
FrameworkElement. For more
information, see Data Binding Overview
and Resources Overview.
Argument # 2.
ElementName points to x:Name, so this name should be found some how. There is a NameScope concept.
For most scenarios, the FindName
methods exposed on FrameworkElement
and FrameworkContentElement are more
appropriate methods to call to search
for elements by name. The Name
properties exposed by FrameworkElement
and FrameworkContentElement are more
appropriate properties to use to set
the initial name as markup attributes.
And the RegisterName methods exposed
on FrameworkElement and
FrameworkContentElement is necessary
to establish a name into a specific
namescope (there is no NameScope
member that can do this directly; you
must set the current namescope first
to use RegisterName).
On the other hand, Visual class neither have FindName method, nor implement INameScope.
I think it's logical tree. When using ControlTemplates, you're replacing one visual tree with another, but I don't think you can reference the names defined inside of the ControlTemplate.
For example:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="Foo" TargetType="Button">
<Border x:Name="border" Background="Red">
<Label Content="{TemplateBinding Content}"></Label>
</Border>
</ControlTemplate>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button x:Name="buttonFoo" Background="Green" HorizontalAlignment="Center" VerticalAlignment="Center" Template="{DynamicResource Foo}">Foo</Button>
<Label x:Name="labelBar" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Background="{Binding ElementName=border, Path=Background}">Bar</Label>
</Grid>
</Page>
Doesn't find the element named "border" in the ControlTemplate, but changing ElementName in labelBar's binding to "buttonFoo" makes the Background Green, as expected.
The ElementName property of a binding in a sense (see below answer) works off of the logical tree because one is using ElementName to divine a specific control solely on the logical tree in the Xaml.
will it lookup visual or logical tree?
The premise you propose is wrong, there is no lookup per-se on either tree. One is simply setting a Source property for reflection operation used by the binding instead of defaulting to the inherited DataContext of the logical tree.
If one reads the documentation of Binding.ElementName Property (System.Windows.Data) (bolding mine):
"...the ElementName property is one of the ways you can explicitly set the source of a Binding and override the inherited data context."
The source is any instantiated object which is within the current operations namespace which can be accessed and reflected off of.
No more no less and most likely will be in the Logical Tree (but doesn't have too) because people name there logical items in Xaml, but also could be in the visual tree.
See Data Binding Overview for more info.
I'm trying to bind the Forderground dependency property to my UIControl, so that it's drawn in the color the user wishes. Since myUiControl.Foderground autocopletes, I thought I could just bind it in the XAML file like this:
{Binding ElementName=rootControl, Path=Forderground}
When debugging VS says it cannot find the source for binding with this DependencyProperty.. but I couldn't figure out why this is.
Also how can I list all dependency properties of an object while debugging?
UPDATE: If below wasn't enough for you, try downloading this sample and looking at it.
The ElementName needs to be set as the "x:Name" of your root control and the Path needs to be set to the Property on the root element you wish to bind to. Without the name it cannot find the element you are referring to (hence the initial error) and without the Path it doesn't bind to the correct property (check your output at runtime for an error).
Try this:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid x:Name="root" Background="Green">
<Button Background="White" Margin="100">
<TextBlock Background="{Binding ElementName=root, Path=Background}" Text="TESTING TESTING"/>
</Button>
</Grid>
Can you confirm that your "rootControl" element is defined earlier in the xaml markup than your Binding holder? Usually the Bindings are bound to the earlier declared elements.
If you mean ImmediateWindow and IntelliSense usage while debugging than each dependency property metadata has usually public static access modifiers. You can for instance type "Control." and observe all the corresponding dependency properties, routed events and attached properties members.
Hope this helps.