I really don't know how to title this question, but I need some help with binding to a ListBox.
I have an object, that contains (among other information) 2 properties that need to be bound in one ListBox. One of these is an ObservableCollection of objects, called Layers, and the other property holds an enum value of either Point, Line or Polygon, called SpatialType. These are to act as a legend to a map application. I have bound Layers to a ListBox, no problem, but inside the ListBox.ItemTemplate, I need to bind the single variable SpatialType to every Item in the ListBox. The problem I'm running into is that when I try to bind while inside the ListBox, the only variables I have access to are the properties of each Layer and I can't access any properties of the original bound class that holds the Layers (and the needed SpatialType property).
What can I do to get that piece of information bound inside the ItemTemplate without messing up a good MVVM architecture?
You can in your view have a ObjectDataProvider that is the basis for your datacontext and have the ObjectInstance point to your viewmodel. Then you can bind from the ItemTemplate like so:
<UserControl.Resources>
<ObjectDataProvider x:Key="Data"/>
<DataTemplate x:Key="Template">
<TextBlock Text="{Binding SpatialType,Source={StaticResource Data}}/>
</DataTemplate>
</UserControl.Resources>
<Grid DataContext={Binding Source={StaticResource Data}}>
<ListBox ItemsSource="{Binding Layers}" ItemTemplate="{StaticResource Template}"/>
</Grid>
Hope this helps.
What I ended up doing was using FindAncestor to get the DataContext of a higher "tier" in binding:
Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.LayerSymbolization.SpatialType, Mode=TwoWay}"
Related
Create window:
<Window
d:DataContext="{d:DesignInstance Type=MyType, IsDesignTimeCreatable=True}"
cal:Bind.AtDesignTime="True">
<ContentControl cal:View.Model="{Binding Model}" cal:View.Context="ViewContext1"/>
</Window>
Create view for view-model named [Root namespace].Model.ViewContext1.
At design time see "Can't find view for view-model".
When run - is all right.
When using Caliburn.Micro in ViewModel first approach, and binding contextual content inside a view to same model (initial ViewModel), make sure to set View.Context before setting View.Model.
You will want to swap them around in this case like so:
<ContentControl cal:View.Context="ViewContext1" cal:View.Model="{Binding Model}" />
I've created a a custom activity designer, but I wanted to have control over the 'header' part (that by default shows the ModelItem.DisplayName), and as far I know, the only way to achieve this is to derive the designer from WorkflowViewElement rather than ActivityDesigner. So, that seems to work and all is well. Except, I want to support the new Annotations feature of WF4.5.
Given that when you add an annotation to a workflow element on the design surface it adds an icon to the element you are annotating + the actual annotation element, it seems clear that any custom WorkflowViewElement has to have some extra stuff in it to support this behaviour. Can anyone help?
Thanks
As I thought, annotations are saved within the workflow definition as an attached property. Here's what an annotation looks like in the workflow's xaml:
<Sequence
xmlns:derp="http://schemas.microsoft.com/netfx/2010/xaml/activities/presentation"
derp:Annotation.AnnotationText="This is an annotation!">
See, just like any other attached property. Except it isn't. Its an attached workflow property, not an attached DependencyProperty. That means it works through the attached property service as well as the Annotation class. Getting and setting the annotation text on a ModelItem is trivial (and covered below).
Its actually not that hard to support annotations. As long as you don't mind your UI looking like crap. Here's a quick and dirty implementation.
In the UI, add some controls for holding and editing the annotation text
<sap:WorkflowViewElement
x:Class="AnnotationSupport.MyActivityDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:ann="clr-namespace:System.Activities.Presentation.Annotations;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
x:Name="root"
MinWidth="100"
MinHeight="100">
<Grid Background="red">
<Grid.RowDefinitions>
<RowDefinition
Height="auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Expander
IsExpanded="False">
<!-- HERE SHE BLOWS -->
<TextBox
Text="{Binding ModelItem.AnnotationText}" />
</Expander>
<TextBox
Grid.Row="1"
Text="{Binding ModelItem.Text}"
Margin="10" />
</Grid>
</sap:WorkflowViewElement>
Any time the Annotation text changes, the ModelItem's PropertyChanged event fires, just like any other property. And if you want to grab it from code, the simplest way is to cast the ModelItem to a dynamic:
private void SetAnnotationLol(string newValue)
{
if(ModelItem != null)
((dynamic)ModelItem).AnnotationText = newValue;
}
Now, if you want to create a nice UI like the Fx Activities have... well...
I'll leave it up to you to create a custom Adorner to handle display and editing of the annotation. Which actually isn't as hard as it first looks. If you haven't done one yet, here's your opportunity.
I have a DataGrid with some text columns and a button. I want to bind button to a command on the ViewModel. Since, Columns are inside the context of the ItemSource, i want to change the DataContext for the button to something outside the DataGrid(to a view model, to access the Command) or else Silverlight is not able to find the binding expression for that command on the ItemSource context.
Here is what i am doing but i am unsuccessful in doing so. I am not sure where i am making a mistake
<DataGrid >
...
<Button>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Path=DataContext.CommandToCall, ElementName=DataGridName}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
...
</DataGrid>
I do not get any Binding error on doing this but i cannot invoke the command inside my ViewModel. Please note, it is for silverlight and not WPF.
Thanks
I had this same problem recently. I was using a Telerik RadGridView, and I found a workaround on their support forum. Maybe you can do something similar.
Here's the question, and here's the workaround.
Suppose I have entity graph like
People ->Student
then in xaml, I have following kind of binding(People is property of VM):
<TextBox Text="{Binding People.Name, Mode=TwoWay}" />
<TextBox Text="{Binding People.Student.StudentNo, Mode=TwoWay}" /> <!-- this bounding is not working -->
in VM, implementing IEditableObject. I have some code like:
public void BeginEdit()
{
((IEditableObject)this.People).BeginEdit();
((IEditableObject)this.People.Student).BeginEdit(); //this code not working
//....
}
When runing the app, all data bound to People is fine.
All data bound to Student is not working.
How to fix it?
I'd guess that the Student property is null on the client side. You need to add the [Include] attribute to the Student property on the server-side, so that it gets taken across to the client side by RIA services. You may also need to add an include for your server-side to retrieve it from the database, depending on how your data-access is written.
Before I explain my issue, consider the following object:
Character.cs
-> AnimationControlSettings.cs
.. -> UpControlType (string)
.. -> AvailableControlTypes (List<string>)
The relevant properties in my ViewModel:
Character SelectedCharacter
ObservableCollection<Character> Characters
I have a simple View where you select a character using a ComboBox. The ComboBox's SelectedItem is TwoWay-bound to the ViewModel's SelectedCharacter property. There are other textboxes/checkboxes (also two-way bound to various properties of SelectedCharacter) that maintain their values properly as I switch between Characters.
The problem exists in the ComboBox bound to the UpControlType property:
<ComboBox x:Name="lstUpControlTypes"
ItemsSource="{Binding Path=SelectedCharacter.AnimationControlSettings.AvailableControlTypes}"
SelectedItem="{Binding Path=SelectedCharacter.AnimationControlSettings.UpControlType, Mode=TwoWay}">
</ComboBox>
Initial values are displayed in this ComboBox correctly but as soon as I switch from CharacterA to CharacterB, CharacterA's UpControl property is set to NULL and I have no idea why.
Here is a barebones repro of this exact issue (VS2010, SL4):
http://www.checksumlabs.com/source/TwoWayBindingWorkshop.zip
If you run that solution you'll see that the Name property persists as you switch Characters but the UpControlType value's getting set to NULL.
Am I missing something obvious here?
You are binding the items source of the third combo box to a property inside the SelectedCharacter, like this:
ItemsSource="{Binding SelectedCharacter.AnimationControlSettings.AvailableControlTypes}"
This means that when SelectedCharacter changes the items source for that combo box will be reset and this activates the two way binding you set in the SelectedItem of the same combo box, setting your property to null:
SelectedItem="{Binding SelectedCharacter.AnimationControlSettings.UpControlType, Mode=TwoWay}"
I was able to fix the issue by moving the property AvailableControlTypes to the CharacterViewModel class, which means that when you change the character, the available types remain the same. If this is acceptable in your situation, it will fix your problem:
<ComboBox x:Name="lstUpControlTypes"
ItemsSource="{Binding AvailableControlTypes}"
SelectedItem="{Binding SelectedCharacter.AnimationControlSettings.UpControlType, Mode=TwoWay}" />