I'm currently using the following itemscontrol and datatemplate:
<UserControl.Resources>
<DataTemplate x:Key="OrdersTemplate">
<dxlc:LayoutItem Label="CustomerReference" LabelPosition="Top" MaxWidth="300" HorizontalAlignment="Left" Width="300">
<dxe:TextEdit IsEnabled="True" Text="{Binding Path=CustomerReference}" />
</dxlc:LayoutItem>
</DataTemplate>
</UserControl.Resources>
<HeaderedContentControl Header="Steps">
<ItemsControl ItemsSource="{Binding Orders}" ItemTemplate="{StaticResource OrdersTemplate}"/>
</HeaderedContentControl>
The source is just a list with entities.
The problem is that the "CustomerReference" of every object from my source changes when I change it in the textbox. Whats missing here?
Greets
I think in your view model you have added the same object more than once. Instead of creating new object when ever you added to the collection. So when you want to add a object to collection create a new object and add it
Related
I am trying to set the DataContext for my datatemplate item BuildStepsViewModel. The below code works perfectly fine.
<StackPanel Margin="10" Name="controlDisplay" Visibility="{Binding Path=Visibility}">
<ItemsControl HorizontalAlignment="Left" ItemsSource="{Binding Path=Elements}" Width="Auto">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type vms:BuildStepsViewModel}">
<local:BuildStepsSelWindow>
<local:BuildStepsSelWindow.DataContext>
<vms:BuildStepsViewModel/>
</local:BuildStepsSelWindow.DataContext>
</local:BuildStepsSelWindow>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
</StackPanel>
Now I am trying to reduce the verbose part in the datacontext set.
<StackPanel Margin="10" Name="controlDisplay" Visibility="{Binding Path=Visibility}">
<ItemsControl HorizontalAlignment="Left" ItemsSource="{Binding Path=Elements}" Width="Auto">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type vms:BuildStepsViewModel}">
<local:BuildStepsSelWindow DataContext="{Binding Path=BuildStepsViewModel}"/>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
</StackPanel>
But now the controls in the BuildStepsViewModel are not displaying correctly. Am I overlooking something?
In the first case the DataContext of is a new instance of vms:BuildStepsViewModel. This does not seem correct, as you want to bind the DataTemplate to an existing instance and not a new one.
In the second case the DataContext is bound to some BuildStepsViewModel property. The source is the old DataContext value. Unless the type BuildStepsViewModel has a property called BuildStepsViewModel, this binding will not work correctly. If I understand the case correctly, you can try omitting the data context, as it will be inherited and it will automatiacally become the correct BuildStepsViewModel instance:
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type vms:BuildStepsViewModel}">
<local:BuildStepsSelWindow />
</DataTemplate>
</ItemsControl.Resources>
These two snippets are not equivalent.
This
<local:BuildStepsSelWindow.DataContext>
<vms:BuildStepsViewModel/>
</local:BuildStepsSelWindow.DataContext>
essentially means
this.DataContext = new BuildStepsViewModel();
So you instantiate a new viewmodel for each view instance.
But this:
<local:BuildStepsSelWindow DataContext="{Binding Path=BuildStepsViewModel}"/>
essentially means:
this.DataContext = this.DataContext.BuildStepsViewModel;
See? That makes no sense. You're trying to access a property named BuildStepsViewModel on the object stored as DataContext. But since there is no data context (yet), the binding returns null, and the data context is not set.
Consider reading thoroughly about the data binding. Also, read about the XAML syntax.
I want to achieve the following:
My ViewModel exposes a property named 'Categories' which is a collection of CategoryViewModel objects
Each CategoryViewModel object exposes a property called 'Items' which is a collection of strings*.
On my View, I want a TabControl with a TabItem for each object in the 'Categories' collection.
The Content of each TabItem should be a xceed DataGrid control displaying the contents of the selected tab's Items collection.
<TabControl ItemsSource="{Binding Categories}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding CategoryName}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<xcdg:DataGridControl
ItemsSource="{Binding Items}"
AutoCreateColumns="True">
</xcdg:DataGridControl>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
This works ok when I bind directly to the ItemsSource property of the DataGridControl. However, in order to utilize all of the functionality of the DataGridControl, I need to bind the ItemsSource property of the DataGridControl to a DataGridCollectionViewSource object that is bound to my Items collection. I do this when the grid ISN'T nested in another control by creating a DataGridCollectionViewSource object in the Resources section of the UserControl and binding to that.
<UserControl>
<UserControl.Resources>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
Source="{Binding Items}" />
</UserControl.Resources>
<Grid>
<xcdg:DataGridControl
ItemsSource="{Binding Source={StaticResource GridData}}"
AutoCreateColumns="True">
</xcdg:DataGridControl>
</Grid>
</UserControl>
How do I need to structure the XAML so that when the TabControl is being bound, a DataGridCollectionViewSource object is created for each TabItem so that the DataGridControl that is generated within the content of the TabItem can be bound to it?
Clear as mud, right? :)
Thanks!
Notes:
*In the real solution the collection contains objects of a class that is more complex than a simple string, but a string was used to make the example more simple.
OK, this is a bit of a long-shot, but could you use the DataGrid.Tag ...
<TabControl.ContentTemplate>
<DataTemplate>
<xcdg:DataGridControl
ItemsSource="{Binding RelativeSource={RelativeSource Self}, Path=Tag}"
AutoCreateColumns="True">
<xcdg:DataGridControl.Tag>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
Source="{Binding Items}" />
</xcdg:DataGridControl.Tag>
</xcdg:DataGridControl>
</DataTemplate>
</TabControl.ContentTemplate>
Or ... resources can be defined on any FrameworkElement, so you could try:
<TabControl.ContentTemplate>
<DataTemplate>
<xcdg:DataGridControl
ItemsSource="{Binding Source={StaticResource GridData}}"
AutoCreateColumns="True">
<xcdg:DataGridControl.Resources>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
Source="{Binding Items}" />
</xcdg:DataGridControl.Resources>
</xcdg:DataGridControl>
</DataTemplate>
</TabControl.ContentTemplate>
I don't use the eXceed Grid so cannot test whether these work - just a couple of ideas to try!
Colin E.
You can use x:Shared="True" attribute on a resource. That means a new instance is created for every use of that resource.
Example:
<UserControl.Resources>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
x:Shared="False"
Source="{Binding Items}" />
</UserControl.Resources>
<UserControl.Resources>
<DataTemplate x:Key="LstBoxTemplate">
<TextBlock Text="{Binding Item}" TextWrapping="Wrap" HorizontalAlignment="Left"/>
<Image Grid.Column="2" Margin="0,0,10,0" Visibility="{Binding isVisible,Converter={StaticResource ImageCtlVisibilityConverter}}" Source="/pjct;component/Images/im.png"/>
</DataTemplate>
</UserControl.Resources>
<ListBox x:Name=lstbox ItemsSource="{Binding itemList}" ItemTemplate="{StaticResource LstBoxTemplate}" />
You question needs more detail, and so I may be missing the point...
If your listbox is bound to a collection of custom objects that you control (aka a view model). Then it should be fairly straight forward for you to add a property to the view model that contains the object that you want to bind your listboxitem to...
I have a combobox defined as follows:
<ComboBox x:Name="cboDept" Grid.Row="0" Margin="8,8,8,8" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Source={StaticResource cvsCategories}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Width="Auto" Height="Auto">
<sdk:Label Content="{Binding CategoryID}" Height="20" />
<sdk:Label Content="{Binding CategoryName}" Height="20" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
It works fine. However, once I select an item in the list, I want a different template to be applied to the combobox selected item being shown to the user (the item shown after the disappearance of popup). In the above case, I want only CategoryName to be displayed in the ComboBox once I select the respective item.
Can anyone let me know on how to achieve this?
thanks
What you need to do is create a ResourceDictionary containing a few defined templates yourself. In the below, ComboBoxTemplateOne and ComboBoxTeplateTwo are user controls that are set out to display the combobox in the manor you want.
<UserControl.Resources>
<ResourceDictionary>
<DataTemplate x:Key="TemplateOne">
<local:ComboBoxTemplateOne />
</DataTemplate>
<DataTemplate x:Key="TemplateTwo">
<local:ComboBoxTemplateTwo />
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
You will then need to create your own class that inherits from ContentControl "DataTemplateSelector", overriding OnContentChanged
Protected Overrides Sub OnContentChanged(ByVal oldContent As Object, ByVal newContent As Object)
MyBase.OnContentChanged(oldContent, newContent)
Me.ContentTemplate = SelectTemplate(newContent, Me)
End Sub
You will then need to create another class that inherits from the above DataTemplateSelector which overrides SelectTemplate ("TemplateSelectorClass"), which will return the DataTemplate defined above ("TemplateOne" or "TemplateTwo").
Also in this derived class, you will need to define a property for each of the templates you have
Public Property ComboboxTemplateOne As DataTemplate
Then head back to your XAML and n the blow XAML
<local:TemplateSelectorClass ComboboxTemplateOne="{StaticResource TemplateOne}" Content="{Binding Path=ActiveWorkspace}>
This should work, as it is effectively doing the same work as setting the "DataTemplate" property in WPF (which doesn't exist in SilverLight)
I realise there are a fair few steps here and its quite fiddly, but hopefully this will get you there. Any questions just shout.
I have the following user control that is embedded within another user control.
<UserControl.Resources>
<DataTemplate x:Key="ContextsTemplate">
<Label Margin="10,0,20,0" Content="{Binding Name}"/>
</DataTemplate>
</UserControl.Resources>
<ItemsControl Name="Contexts"
Background="Transparent"
ItemsSource="{Binding}"
Margin="0,0,0,0"
VerticalAlignment="Center"
AlternationCount="2"
ItemTemplate="{StaticResource ContextsTemplate}">
</ItemsControl>
Here is XAML code for the user control (controlB) above that is embedded in another user control (controlA).
<local:ContextContentsUserControl Height="30" Content="{Binding Contexts}"/>
controlA is displayed on the screen as "(Collection)" but for some reason doesn't show each item in the collections text in the label. Please help.
The problem is here:
Content="{Binding Contexts}"
You meant:
DataContext="{Binding Contexts}"
The reason you got "(Collection)" instead of the content you had defined for controlA is the content you defined in the XAML for ControlA was replaced with your collection. The body of a UserControl's XAML file simply sets its Content property: You replaced it after it was set.
When you declare your ContextContentsUserControl, you are setting its Content property. You need to be setting the DataContext instead:
<local:ContextContentsUserControl Height="30" DataContext="{Binding Contexts}" />