I have a WPF application using MVVM pattern, where I have many ObservableCollections. Instead of putting these ObservableCollections into each ViewModel, I placed them into a static class called Observables, which is a member of static class AppCommon. So I can access all observable collections through AppCommon.Observables.AnyObservableINeed.
Now I need to change bindings of UserControl's so they bind to these global ObservableCollection's but I don't know how to refer to these ObservableCollections without changind the DataContext.
I tried adding namespace like
xmlns:globals="clr-namespace:Demirbaş.Globals"
and then in the ListBox setting the ItemsSource property like
<ListBox ItemsSource="{Binding Source={globals:Observables.TaşınırSınıfları}}"
but that would give me following error:
'{globals:Observables.TaşınırSınıfları}' value is not a valid MarkupExtension expression. Cannot resolve 'Observables.TaşınırSınıfları' in namespace 'clr-namespace:Demirbaş.Globals'. 'Observables.TaşınırSınıfları' must be a subclass of MarkupExtension.
What is the problem here? Am I using the right XAML syntax to bind to these collections?
EDIT
ItemsSource="{Binding Source={x:Static globals:AppCommon.Observables.TaşınırSınıfları}}" gives me error :
Cannot find the type 'AppCommon.Observables'. Note that type names are case sensitive.
I think it cannot refer to nested classes, is it right? What's the solution?
Thanks
I don't know the namespace of your application but try
xmlns:local="clr-namespace:Demirbaş"
<ListBox ItemsSource="{Binding
Source={x:Static local:AppCommon+Observables.TaşınırSınıfları}}" />
You need to use the x:Static markup extension like LPL suggested in a comment to tell WPF it's a static object
<ListBox ItemsSource="{Binding
Source={x:Static globals:Observables.TaşınırSınıfları}}" />
This error can also occur when the namespace reference is not fully qualified and the target binding exists in another assembly.
For example, xmlns:l="clr-namespace:AssemblyA.Namespace;assembly=AssemblyA".
If the specific assembly is not specified, the same error message will be displayed "value is not a valid MarkupExtension expression".
Related
I am trying to understand what the format is for the DataType parameter for a DataTemplate or a HierarchicalDataTemplate. There are lots of examples scattered throughout the internet that I can copy and get working, but I don't understand what my options are.
For example:
<DataTemplate DataType="{x:Type model:DepartmentSelectionViewModel}">
I would like to understand what x:Type means. And what model:DepartmentSelectionViewModel means.
Or:
<HierarchicalDataTemplate DataType="{x:Type r:NetworkViewModel}" ItemsSource="{Binding Children}">
Again, it has x:Type. But this time r:NetworkViewModel.
Other examples will have sys: or local:. What do all these settings mean? How can I discover what other settings exist? (Is settings even the right word to describe them?)
model and r refer to XAML namespace mappings.
These are ofter found in the root tag or the XAML file and define the CLR namespaces in which the types (classes) DepartmentSelectionViewModel and NetworkViewModel are defined respectively:
<Window ... xmlns:model="clr-namespace:Project1" ... />
namespace Project1
{
public class DepartmentSelectionViewModel { ... }
}
You can define as many namespace mappings as you want.
x:Type refers to a type for which the implicit DataTemplate will be applied, i.e. the DataTemplate with the DataType property set to {x:Type model:DepartmentSelectionViewModel} will be applied to all DepartmentSelectionViewModel objects in the Items collection of the TreeView when the view is rendered.
I am trying to bind the ItemsSource of my ComboBox to a static dictionary I have on a static class.
In WPF I would use the following which would work fine:
ItemSource="{x:Static objectModel:LocaleHelper.FriendlyNames}"
Where LocaleHelper is the class name and FriendlyNames is the dictionary property of which I wish to bind to.
However in Silverlight I get an error to do with the type x:Static not being found.
Could anyone explain to me what the issue is and the workaround?
I have looked around but couldn't find any detailed explanations.
Sorry if this is a simple issue - I'm new to Silverlight and also WPF in general.
EDIT:
After having done some more reading it looks like silverlight does not support static resources. Furthermore Dictionaries do not seem to update property changed / support DisplayMemberPath & SelectedValue so having the dictionary as a field in my viewmodel doesn't seem to be an option either.
You can only bind to non-static public properties (not fields). But you can use any "carrier" for those properties (so you are not forced to have those properties in the ViewModel). Let's see...
<Resources>
<LocaleHelperWrapper x:Key="Wrapper"/>
</Resources>
<ComboBox ItemsSource="{Binding Path=FriendlyNames,
Source={StaticResource Wrapper}}"/>
And the wrapper code:
public class LocaleHelperWrapper
{
public Dictionary<string, string> FriendlyNames
{
get { return LocaleHelper.FriendlyNames; }
}
}
[Edit] The ComboBox supports DisplayMemberPath and SelectedValue. Assuming you want to use the ComboBox to select the Key and display the Value of you Dictionary's KeyValuePairs:
<ComboBox
DisplayMemberPath="Value"
SelectedValuePath="Key"
SelectedValue="{Binding Path=MySelectionViewModel.SelectedKey, Mode=TwoWay}"
ItemsSource="..."/>
If it's merely an issue of binding to a collection, you might as well do it in the constructor of the ViewModel. Further consider using an ObservableCollection in case your static collection changes over time.
I use MVVM for my application, the DataContext of controls is assigned in my c# code (not in XAML).
Therefore the XAML controls have no idea to which instance type its DataContext is set to. The consequence is that there is no refactoring support and intellisense for the bound properties of my viewmodel in XAML.
Is there a way to tell a control in XAML to which type its DataContext is linked?
So when I modify a property name in my ViewModel or search for all references of that property, I want that this property in XAML bindings gets considered too.
There is no framework support, the best you can do is tell the VS designer the 'shape' of the DataContext so that it will give you hints for the properties. If you want to make your solution more refactor-proof, I would recommend Daniel's T4 metadata solution:
http://www.codeproject.com/KB/codegen/T4Metadata.aspx
This generatesmetadata for your view models which you can reference in the XAML:
<StackPanel DataContext="{Binding Source={StaticResource Person}}">
<TextBlock >Name:</TextBlock>
<TextBox Text="{Binding Path={x:Static Metadata:PersonMetadata.NamePath}}"/>
</StackPanel>
Colin E.
No, as the DataContext can change at runtime, it doesn't make sense to tie this to a particular type.
I've got a treeview bound to an XmlDataProvider following this example. The app I am working on is following the MVVM pattern and the Xml is from a file that the user will open.
When I try to bind the Source property of the XmlDataProvider like so
<XmlDataProvider Source="{Binding Path=XmlFilePath}"/>
I get a "Binding can only be applied to a DependencyProperty of a Dependency object." or somesuch.
So short of cobbling the binding together procedurally is there a way to declaratively bind the XmlDataProvider Source? If I try to forgo the data provider and bind the tree directly to an XmlNode property I get an error about using XPath binding only with Xml objects; which makes absolutely no sense to me but I'm sure it's trying to tell me something important.
The answer appears to be: you can't.
I was able to solve my underlying problem (binding a treeview to an Xml document) by removing the XmlDataProvider from the equation and binding the TreeView directly to a ViewModel property that returns an XmlNode.
What had been tripping me up was that I took the binding code that pointed at the XmlDataProvider and pointed it at my property, leaving the XPath argument in place.
<TreeView ItemsSource="{Binding Path=ProjectDocument XPath=.}">
This would result in a runtime error: System.Windows.Data Error: 44 : BindingExpression with XPath cannot bind to non-XML object.; XPath='.'
Which was not the most helpful. What it was really trying to say is that you can't bind to an XmlNode property AND provide an XPath argument in the binding (because it's the XmlDataProvider that knows what to do with that??).
<TreeView ItemsSource="{Binding Path=ProjectDocument}">
actually that was rather tough problem for me, cause I needed the app to load treeview from temp file, and assuming application can have different locations, I can't set strict link in the XmlDataProvider Source property;
Add source as resource to the project
the solution I found is adding temp file (markup is created via XAML, see below) to the project with build action set to Content thus, application reloads it every time you call InitializeComponent() on the object containing XmlDataProvider and my treeview updates.
<XmlDataProvider x:Key="dshPreview"
Source="~tmpConstruct.xml"
XmlNamespaceManager="{StaticResource argNms}"
IsAsynchronous="true"/>
TreeView is bound like this:
<TreeView x:Name="PreviewTree"
ItemsSource="{Binding Source={StaticResource dshPreview},
XPath=/mns:engine/mns:ws}"
/>
Maybe this will help someone
I didn't find how to bind the source straight away, but you can change the XmlDataProvider source in the code behind as following:
var xdp = (XmlDataProvider)this.Resources["key-of-your-XmlDataProvider-in-resources"];
xdp.Source = new Uri("http://url-of-your-xml");
You can use that combined with an event handler to bind.
For example I have the following binding markup
Text="{Binding Path=FirstName}"
pretty simply but it could be much more complex, I need to be able to parse this markup and get it into some objectified form such as an instance of the Binding class.
Something that could work in reverse, an instance of the binding class to spit out the markup would be great as well.
I know such a thing must exist in the framework but I dont know where/what class.
I have looked at XamlReader but was unable to get it working because in this case I am missing context as I am only working with bits of the project and not the whole.
You can get the Binding object using GetBindingExpression, for example if you have:
<TextBlock Name="MyTextBlock" Text="{Binding Name}"/>
You can use:
BindingExpression expr = BindingExpression.GetBindingExpression(MyTextBlock, TextBlock.TextProperty);
Binding bindingObject = expr.ParentBinding;
To use XAMLReader you have to surround it with a valid root. then this shoudl work.