I have a WPF ComboBox created in XAML:
<ComboBox DockPanel.Dock="Top" Background="{DynamicResource Esri_BackgroundPressedBrush}" DataContext="DockpaneData"
Foreground="{DynamicResource Esri_TextMenuBrush}" HorizontalAlignment="Stretch" FontSize="14" VerticalAlignment="Center" Margin="5,0,5,0" IsEditable="True" Text="Jump To"
ItemsSource="{Binding FeatureEditUpdates}">
</ComboBox>
I set the DataContext of the ComboBox "DockpaneData", which in this case is an internal class called "DockpaneData" within another file called DockpaneViewModel.cs.
Why Can't I bind to the public class property "FeatureEditUpdates"?
It will work if I put it in the class with the same name as the file, and DON'T set the datacontext in the ComboBox. Why?
The error I'm getting in the output window is:
System.Windows.Data Error: 40 : BindingExpression path error: 'FeatureEditUpdates' property not found on 'object' ''String' (HashCode=-1567065443)'. BindingExpression:Path=FeatureEditUpdates; DataItem='String' (HashCode=-1567065443); target element is 'ComboBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
Where I see it thinks the datacontext is a string, which doesn't make sense to me.
Thank you!
The expression
<ComboBox ... DataContext="DockpaneData"/>
sets the DataContext of the ComboBox to the string literal "DockpaneData", which you see in the error message
property not found on 'object' ''String'
One way to set the DataContext correctly is to declare and use a XAML resource:
<Window.Resources>
<local:DockpaneData x:Key="DockpaneData"/>
</Window.Resources>
...
<ComboBox ... DataContext="{StaticResource DockpaneData}"/>
Related
Really annoying issue. The code seems to work fine, but when run, I see this error being thrown up:
System.Windows.Data Error: 40 : BindingExpression path error: 'IsOpen'
property not found on 'object' ''MainViewModel' (HashCode=33664731)'.
BindingExpression:Path=IsOpen; DataItem='MainViewModel'
(HashCode=33664731); target element is 'Popup' (Name='LoginPopup');
target property is 'IsOpen' (type 'Boolean')
I understand there is some sort of issue where IsOpen property of LoginPopup binding is being attempted on the MainViewModel and failing because there is no IsOpen property in the MainViewModel. Fine and good, but the DataContext I'm binding to is not the mainviewmodel, but the LoginPopupViewModel (LoginPopup in the ViewModelLocator class). Intellisense seems to agree with me that things are bound to the LoginPopupViewModel, as if I type other things in the Binding portion of IsOpen, it complains that, "Cannot resolve property in data context of LoginPopupViewModel", as it should.
Here's a portion of the XAML code:
<Popup x:Name="LoginPopup" PlacementTarget="{Binding ElementName=LoginButton}"
Placement="Bottom"
HorizontalOffset="-40" VerticalOffset="35" StaysOpen="False"
IsOpen=" {Binding IsOpen}"
DataContext="{Binding LoginPopup, Mode=OneWay, Source={StaticResource Locator}}"
Grid.ColumnSpan="3" Grid.Column="0"
Margin="0,0,0.333,0"
Grid.Row="0" Grid.RowSpan="2">
I'm not exactly a master of WPF, so I'm probably missing something, or the sytax is wrong here. Any help would be fantastic! Thanks!
You are getting that error because DataContext binding is afterIsOpen binding, so when the parser comees across IsOpen the DataContext is currently MainViewModel (set by dependency property inheritance). Then WPF processes the DataContext={..} and re-evaluated the IsOpen binding.
E.g. 2 bindings ultimately the same, but one showing an error
This gives an error in output, but works
<TextBlock Text="{Binding TextB}" DataContext="{Binding B}"></TextBlock>
This doesn't give error
<TextBlock DataContext="{Binding B}" Text="{Binding TextB}"></TextBlock>
Original Answer
The error you are getting is because this:
IsOpen="{Binding IsOpen}"
cannot be bound successfully.
You are binding the DataContext of it to {StaticResource Locator}, and a property LoginPopup on that resource. I am assuming Locator.LoginPopup return a MainViewModel?
What is Locator.LoginPopup and what are you trying to achieve by IsOpen="{Binding IsOpen}"? Is that a property on some view model?
I am working on a MVVMLight / WPF project and need to add a chunk of functionality which will include multiple views and viewmodels. I know this same bit of functionality will be used in other projects in the near future so I would like to make this functionality its own project that I can add to other solutions as needed wiuth little or no modification.
I started by adding a second MVVMLight project (Beta), removing the standard MainWindow.xaml and MainViewModel.cs files and created a simple UserControl and associated View Model.
<UserControl x:Class="Beta.View.TestView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ignore="http://www.ignore.com"
mc:Ignorable="d ignore"
DataContext="{Binding Test_VM, Source={StaticResource Locator} }">
<Grid>
<TextBlock Text="{Binding WelcomeMessage}" />
</Grid>
</UserControl>
public class TestViewModel : ViewModelBase
{
#region Properties
public string WelcomeMessage
{
get
{
return "Hello World!";
}
}
#endregion Properties
#region Constructors
/// <summary>
/// Initializes a new instance of the TestViewModel class.
/// </summary>
public TestViewModel()
{
}
#endregion Constructors
}
I am able to add Beta as a reference to the original project (Alpha) and display the view by inserting the view into a stack panel like so:
<StackPanel Name="MasterStackPanel"
DockPanel.Dock="Top">
<beta:TestView />
</StackPanel>
Everything appears to work properly when doing this. The issue I am having is when I try to bind a Property from TestViewModel to TestView.
In TestView, if I do this:
<TextBlock Text="Hello World" />
the TestView displays correctly at runtime. But when I bind the TextBlock to a property like so:
<TextBlock Text="{Binding WelcomeMessage}" />
The message does not display and the locator for Beta appears to be ignored (the datacontext is not being bound) and I am getting the following error from Snoop:
System.Windows.Data Error: 40 : BindingExpression path error: 'WelcomeMessage' property not found on 'object' ''MainViewModel' (HashCode=51013215)'. BindingExpression:Path=WelcomeMessage; DataItem='MainViewModel' (HashCode=51013215); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'Test_VM' property not found on 'object' ''ViewModelLocator' (HashCode=22749765)'. BindingExpression:Path=Test_VM; DataItem='ViewModelLocator' (HashCode=22749765); target element is 'TestView' (Name=''); target property is 'DataContext' (type 'Object')
I believe this means that the binding of Test_VM & WelcomeMessage are trying to be found via the Alpha Locator and not the Beta Locator. I am using the ViewModelLocator that is created by default when starting a MVVMLight project in each project.
Is it possible to have an second 'Locator' and if so what do I need to do to make it work?
I think you should only have one Locator in the application root of the system and use the "MvvmLightLibs" library in the library project and reference it in the alpha project and add a TestViewModel-Property in the locator.
My UserControl requires binding to the ancestor (the ancestor being the MainWindow) and to itself (it's code behind).
To bind to the ancestor, I'm using
DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1,AncestorType=Window}}">
To bind a control to the code behind (and thus using the 'local' DataContext), I'm using
<TextBlock Text ="{Binding MyUC3Property}" Name="MyName" />
and in the code behind, setting it like
this.MyName.DataContext = this;
The above works fine, where I can bind to the codebehind and to the ancestor.
Now, I still want to bind to the code behind and the ancestor but set the DataContext in the XAML only (if possible).
I've tried
<TextBlock Text ="{Binding MyUC3Property}" DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}" />
and ensured the constructor does not set the DataContext (since I want it all done in the XAML) - (although even if I do set this.DataContext = this; the error persists)
and the output window tells me there is a binding error.
System.Windows.Data Error: 40 : BindingExpression path error: 'MyUC3Property' property not found on 'object' ''TextBlock' (Name='')'. BindingExpression:Path=MyUC3Property; DataItem='TextBlock' (Name=''); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
I guess I'm missing something obvious, but I can't tell what.
You should be able to bind to the user control the same way as you do to the window:
DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1,AncestorType=UserControl}}">
What you have tried was referring to the relative source Self from the TextBox. However, in that context, Self refers to the TextBox, not to the enclosing user control.
for usercontrols you should never set the datacontext to self. check to comment from H.B. from here
i use ElementName Binding
<UserControl x:Name="uc">
<TextBlock Text="{Binding ElementName=uc, Path=MyDependencyPropertyDefinedInMyUserControl}"/>
using the usercontrol:
<Window>
<MyUserControl MyDependencyPropertyDefinedInMyUserControl="{Binding Path=MyValueForTheTextBox}"/>
i try to explain it a little bit for your textbox case (ignor my poor english btw :))
if you want create a usercontrol with a textbox and this usercontrol/textbox should show the text from differrent viewmodels in different views - then you have a problem as far as the viewmodels have different propertynames. now the dependency property in your usercontrol come into the game. you create a DP where all your viewmodels can bind to and you bind your textbox within your usercontrol just to the DP from your usercontrol.
First thing is that you should probably push your parent DataContext to the lower levels. This will give you "God" ViewMode shared between all nested screens.
Second is that you should probably use something like MVVMLights Messanger to have cleaner separation.
In WPF I have the following structure:
UserControl > Grid > TabControl > DataGrid > ContextMenu
I would like to have the DataContext of my ContextMenu the same as the one for my Grid. This is how I am currently trying to do it:
<ContextMenu Name="contextMenu" DataContext="{Binding ElementName=MainGrid, Path=DataContext}">
But I get the following error:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=MainGrid'. BindingExpression:Path=DataContext; DataItem=null; target element is 'ContextMenu' (Name='contextMenu'); target property is 'DataContext' (type 'Object')
I need to do it this way as the DataContext of the DataGrid is different from the "MainGrid", and the ContextMenu is in the DataGrid.
Can anyone offer me some guidance as according to me this is correct?
I feel that is not required. The DataContext set at the parent level is already available to the child. You can override, if you need. But in your case you want to use the same Datacontext.
normally you would bind a property to your specific DataContext, and not the DataContext itself to another DataContext. But in your case, this should help:
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}, Path=DataContext}"
I have a problem with my data binding, probably a small one. I have tried to implement the MVVM pattern in my application. Therefore I have a model containig my data. This data gets updated over the network in a periodic way. On top of this model I have a view model to bind to. In this view model I have a ObservableCollection, which I want to bind. The problem I have is, that my view model needs to be a global resource. Thats why I use the following attempt in my NavigationWindow :
<NavigationWindow.DataContext>
<localvm:DataViewModel/>
</NavigationWindow.DataContext>
The reason I have to use it as a global variable is, that this view model starts my network business logic. Thats probably a bad way but I could'nt find a solution to this. Anyway
to diplay my data I have a Frame in my NavigationWindow defined like this:
<Frame Source="/Views/Pages/Page1_SystemOverview.xaml" VerticalAlignment="Stretch></Frame>
in this loaded page I have a ItemsControl to view the Collection:
<Page>
<Grid>
<Grid.Resources>
<localcnv:DebugHelperConverter x:Key="debugCNV"/>
</Grid.Resources>
<StackPanel>
<ItemsControl ItemsSource="{Binding Source=ListOfQuerys}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Content="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=(ItemsControl.AlternationIndex)}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
So here is my problem: When I start my program The ItemsControl contains 18 elements with no content at all. It should contain only two elements, the output window shows me no binding errors, but when I change the ItemsSource to
"{Binding Path=ListOfQuerys}"
it says:
System.Windows.Data Information: 41 : BindingExpression path error: 'ListOfQuerys' property not found for 'object' because data item is null. This could happen because the data provider has not produced any data yet. BindingExpression:Path=ListOfQuerys; DataItem=null; target element is 'ItemsControl' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
What am I doing wrong? I thought, when I set the DataContext in a parent class, I can use it down the tree but somehow it won't work, any Ideas?
Thanks!
The content of the Frame element is not part of visual / logical tree and hence will not persist the data context. You will have to set it explicitly.
<Frame Source="Page1.xaml" Navigated="Frame_Navigated"/>
private void Frame_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
((FrameworkElement) e.Content).DataContext = this.DataContext;
}
Hope this helps...
try to change
<ItemsControl ItemsSource="{Binding Source=ListOfQuerys}">
by
<ItemsControl ItemsSource="{Binding Source=ListOfQuerys, Mode=TwoWay}">
If ListOfQuerys is a property of your datacontext object make the following binding :
<ItemsControl ItemsSource="{Binding ListOfQuerys}">
The source is your datacontext by default, ListOfQuerys here is the path.