Binding DataContext in XAML With DataContext Set In Code - wpf

I have the following code:
ProcessMainWindow.xaml.cs
public ProcessMainWindow(SourceTableRowInfo rowContent)
{
InitializeComponent();
this.DataContext = rowContent;
}
ProcessMainWindow.xaml
<!--Insert Code---->
<TabItem x:Name="postProcessTab" Header="Post-Processes">
<local:PostProcessUserControl PostProcessItem="{Binding PostProcess, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</TabItem>
So RowContent has an element called PostProcess in it. I am trying to bind that element to a UserControl Dependency Property, but cannot get the binding to work. Based off what I was reading here (Using the DataContext) my understanding is that what I have should work, but I can't get it to work. So am I misunderstanding what it is saying? I have read a few other pages but still can't figure it out.
I have also tried:
<!--Insert Code---->
<TabItem x:Name="postProcessTab" Header="Post-Processes">
<local:PostProcessUserControl PostProcessItem="{Binding, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Path=PreProcess}" />
</TabItem>
If these are correct, I guess I have an error elsewhere in my code. I have yet to fully understand data binding in WPF to know if that is the case though so any help would be appreciated.

One thing to try is to put a trace on the Binding:
PostProcessItem="{Binding PostProcess, PresentationTraceSources.TraceLevel=High}.
Then look for what it tells you at runtime in the Output pane in VS. This can help you identify cases where your DataContext isn't what you think it is, or your Path is misspelled -- all the simple stuff that the compiler catches in C# but can't be detected at compile time in a late-binding/duck-typed miasma like XAML.
Don't leave those traces on bindings once you're done with them; they can really slow things down. Or at least set TraceLevel=None, to save trouble if think you'll be coming back to one later.

Related

Issue when attempting to get WPF combo box to bind to List<T>

I have a custom class called ApplicationUser which has a number of properties. The ones of importance here are GivenName and Surname.
In the ctor for the window I have code which returns a List called _allUsers. This call is successful and the list is filled with the appropriate number of ApplicationUsers
So I then do something like:
_allUsers = CachingLayer.Get<List<ApplicationUser>>("allUserInformation");
cboListOfUsers.DataContext = _allUsers;
And the XAML:
<ComboBox Name="cboListOfUsers" ItemsSource="{Binding}" IsEnabled="{Binding Path = IsChecked, ElementName=rbAssignedTo}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text >
<MultiBinding StringFormat=" {0}, {1} ">
<Binding Path="Surname" />
<Binding Path="GivenName" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
But there's no joy (the Combo Box remains resolutely empty)
What am I doing wrong here?
OK then you need to set you DataContext to the code behind as a whole up in the top in Window
DataContext="{Binding RelativeSource={RelativeSource self}}"
Make AllUsers a public property that returns allUsers
Bind to AllUsers
ItemsSource="{Binding Path=AllUsers}"
It was the BindingExpression path error: 'GivenName' property not found on 'object' ''ApplicationUser' error message that finally solved it for me!
This is going to make everyone sick, but as I was preparing to edit my question to include some screenshots to prove that "The blasted thing does have a property called x and y and what the hell does the Output window know!" I said I'd better check that I had implemented the object ApplicationUser correctly.
Sure enough I hadn't, I had left what I had thought were properties as publicly mutable fields(!). I turned them into auto-props and then my code as originally posted worked.
I'd like to apologise to and thank all who read the question, commented and suggested answers. My purpose in leaving this answer here is twofold, to help anyone else out that may find themselves in a similar situation and also to serve as a reminder to myself that sometimes if you can't see the wood for the trees then you may need to step back a bit.
I think your issue is in timing which is caused by where your are assigning DataContext. XAML resovles
ItemsSource="{Binding}"
during the InitializeComponent(), but you might be iinit'ing list after, which is too late.
When XAML gets build/resolved, comboBox takes the Binding, but there is nothing there. Many ways to solve:
the easiest way, is to do it in XAML:
why even set DataContext, doesn't look like you're doing anything special, it's only a list, not a full blown ViewModel..
remove:
cboListOfUsers.DataContext = _allUsers;
add/replace with
cboListOfUsers.ItemsSource = _allUsers;
3.Init your _allUsers before InitializeComponent(), then assign it to the DataContext
One more suggestion - debug your bindings in xaml, add:
ItemsSource="{Binding, diagnostics:PresentationTraceSources.TraceLevel=High}"
check you output window, if you have an exception, then I am right, the binding tries to resolve, but there is nothing there...
I think that should work..
Also, check out this post:
Why are DataContext and ItemsSource not redundant?

Binding three levels down in the data hierarchy

It's a good thing I don't mind feeling stupid.
I'm trying to bind to an ObservableCollection on my view model. The data hierarchy looks like: Parent -contains list of- Child objects. Nothing complicated.
At the outermost grid of my Xaml tree I establish a link to the view model with:
<Grid DataContext="{StaticResource src}">
Yes, src does reference the view model and the two dozen bindings before the problem textbox work fine. There is not another DataContext in my Xaml tree. Now I come to a simple textbox. I want to bind Textbox text to a child.property.
This works:
<TextBlock
DataContext="{Binding Parent}"
Text="{Binding Path=Child.Property}"
Style="{StaticResource headerMajor}"
/>
This doesn't work:
<TextBlock
Text="{Binding Source=Parent,Path=Child.Property}"
Style="{StaticResource headerMajor}"
/>
I thought they were two ways of saying the same thing. Ordinarily I wonder for a moment and then keep on coding. However, some advice I've read mentioned that DataContext attributes buried in Xaml controls can lead to hard to find bugs.
Please explain why one works and the other does not. This will help my grasp on the whole binding topic.
Jim
Source is a property which holds an object used as source for the binding, it does not resolve to a property. Hence your binding is looking for the property path Child.Property on the string "Parent", see the problem?

SelectedItem of SelectedItem

first of all I would like to thank you for the many good posts that i read in this forum. Unluckily I could not find anything of help for my current problem (either here or anywhere else).
What I'm trying to do sounds quite simple, but I have no clue how to get it to work ... perhaps I'm still to new to wpf or I don't thing wpfy enough :)
I'm designing a front end for a part in an automated manufacturing:
I have a quantity of places where pallets can be put (but it can be empty as well).
Each pallet has up to 3 places where parts can be mounted
Everything is created dynamically of a database and is reacting to changes.
The position of the parts on the pallet comes from the database as well and should be visualized
What I would like to have is:
An overview over the pallet-places with a preview of the pallet
When I select a place I want to see a detail view of the place
When I click on a part on the pallet of the detailed pallet I want to see details to the part
The first two points are quite simple and work nicely:
I have got a DataTemplate for every component (part, pallet, pallet-place). Actually those are UserControls that are imported as Datatemplates
the overview is a ListBox with the places as DataContext
for the detail-place-view I use the UserControl and bound it to the SelectedItem of the Listbox
I tried to bind the Text of a Textblock to the ID of the selected Part ... and fail.
Probably I could use some global variables in the code behind - but that sound very ugly.
Can anybody help?
I have got a solution ... it is not nice but works.
I created an event in the pallet, that triggers, when the selected part-place changes
I handle the event in the pallet-place and create a new one
And finally I handle it in the overview and change the detailview accordingly
Most likely there are much nicer solutions, but it will suffice.
Perhaps try an ElementName binding?
<TextBlock Text="{Binding ElementName=Name_of_your_Listbox, Path=SelectedItem.ID" />
Can you post a bit more code of your TextBlock and your Binding?
Context is important, if i use a ContentControl and bind its content to the SelectedItem like this:
<ContentControl Content="{Binding SelectedItem, ElementName=mylistbox}">
I can bind to the ID of the selected item in the DataTemplate like this:
<ContentControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding ID}" />
</DataTemplate>
</ContentControl.ContentTemplate>
That is because setting the Content of the ContentControl automatically sets the DataContext as well, and this binding is relative to the DataContext since no source (ElementName, RelativeSource, Source) has been specified.
I do not know how your UserControl handles the context, if the DataContext is not affected such bindings will not work. You would need to bind directly then:
<uc:MyDetailsView Data="{Binding SelectedItem, ElementName=mylistbox}">
<!-- ... -->
<TextBlock Text="{Binding SelectedItem.ID, ElementName=mylistbox}" />
This of course defeats the purpose of having the binding on the UserControl itself in the first place. But unless you post some relevant code it's quite hard to tell what is wrong.
Also check the Output window in VisualStudio, binding errors will show up there and might provide valuable information as to what went wrong.

RelayCommand called in "old" DataContext

I am using RelayCommands in my ViewModels to ged rid of the code behinds. The RelayCommands are working, except in this situation: the ViewModel in which the RelayCommands are defined is changed with the change of the datacontext. If a command is being fired after the datacontext change, it is fired in the "old" viewmodel. While debugging I can see that the properties are from the old datacontext. But in the view is everything fine because the correct data of the correct viewmodel is displayed.
So is it possible that the bounded commands are not able to react to a change of the datacontext?
Or might there something else being wrong?
Here a snip of the code:
<TabControl x:Name="TestView" DataContext="{Binding Path=SelectedParentElement}"
TabStripPlacement="Top" ItemsSource="{Binding Path=ChildElements, Mode=OneWay}"
SelectedValue="{Binding Path=SelectedChildElement, Mode=TwoWay}">
<TabControl.ContextMenu>
<ContextMenu>
<MenuItem Header="Klassifikation" Name="Klassifikation">
<MenuItem Header="Kindebene" Name="KlassisfizierendNext" Command="{Binding KlassifizierendNextCommand}"/>
</MenuItem>
</ContextMenu>
</TabControl.ContextMenu>
.......
</TabControl>
The datacontext of the tabcontrol is correctly changing, but after changing the command is being called in the old datacontext.
Found a solution: http://social.msdn.microsoft.com/Forums/en/wpf/thread/2cbec263-df05-4000-9077-35861fc2fa8e
But it seems to be a bug that the datacontext auf contextmenus dont change right.
#Rick. The reason for the downvote:
It doesn't answer the OP's question. He's debugging the data context, you're doing everything in XAML.
It doesn't work for me. I assume that this is due to the same bug that the OP noticed.
To be fair, this isn't your fault: it's clearly a bug in the way that Microsoft is handling DataContext inheritance for ContextMenus, but your answer doesn't appear to have solved the OP's problem, nor mine.

Silverlight 4: "Invalid XAML" using Converter in DataTemplate

maybe you could help me understand why I get an unhandled exception "Invalid XAML" in Visual Studio 2010 designer when trying to do the following on a Page.
I have a Converter named DateTimeConverter that converts a date into a German date string. The converter works fine. I've included the namespace and added the following to the page's resources:
<navigation:Page.Resources>
<myClasses:DateTimeConverter x:Key="dateTime" />
</navigation:Page.Resources>
Now I have a list box that I want to bind to a list of objects. I do the binding in code, but I would like to define the data template. Thus I've added the following to my layout:
<ListBox x:Name="lbConversation" BorderBrush="#00000000">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0" Padding="4">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Message, Mode=OneWay}" />
<TextBlock Text="{Binding TimeStamp, Mode=OneWay, Converter={StaticResource dateTime}}" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And this works fine when I run. However, in the code section, the code for the data template is undercurled and the designer says "Invalid XAML". When I remove the Converter=... part, this error is gone.
Is this a designer bug? What can I do?
EDIT
By the way: The exact same code does not throw the error within a WPF project!
Just adding to this question as I found a solution.
The solution to my case was here: http://forums.silverlight.net/post/618518.aspx
Apparently you must not have a space character in your project name or assembly name. D'oh!
Hope it helps.
Sorry, can't replicate this at all, do you have some design-time data that may be the cause of the weird error?
Also, since you said that you're using the converter to output german dates... wouldn't it be easier to let the framework do this kind of things, as it probably does them a lot better? Set the entire application thread's CultureInfo to german and all formatting will be done with that culture's settings; of course it's still possible you only want some controls internationalized...
I can't see anything wrong with your Xaml however I wonder if this is a result of the language setting used when the Xaml is parsed. By default Xaml is parsed using the InvariantCulture however it would appear that the designer in visual studio parses the Xaml using the current culture. Hence at times you can get unexpected differences in behaviour at design time than you do at runtime.
In fact if you do this in the constructor of your UserControl before calling InitializeComponent:-
this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);
You might not need your converter at all.
I came across "Invalid XAML" error when I had my converter marked internal. Change the modifier to public and everything is as expected.
Hope this help.

Resources