Datacontext of usercontrol is null - wpf

I have a viewmodel with an observablecollection member.
I created a usercontrol that binds with this collection and for every item in the collection I end up in the user controls constructor. In this constructor the datacontext is null, why is that?
<ItemsControl ItemsSource="{Binding ListOfMyCustomType}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<uc:Tile DataContext="{Binding Path=.}"></uc:Tile>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Edit:
There are no BindingExpression errors in the debug output.
Edit:
Solved by Matthias, the datacontext is not available at this time. It will be available when the control is loaded or when the datacontext changes. Thumbs up!
Regards,
Michel

I would remove the DataContext attribute and binding expression. Your user control will take on whatever item (inside the collection that the ItemsControl is bound to) is being bound to the current item's template.
Then in the loaded event of your control you should be able to access its DataContext:
var dataContext = this.DataContext as YourCustomType;

Related

with MVVM is a good practice to add controls to wrap pannel from the view model?

I have an application in WPF that use the MVVM pattern and I use to have a list or observableCollection for example to binding comboBox, DataGrids... etc. However I have a control and I would like to add dynamically items of this control to the wrap pannel.
is a good idea in my view model create the view and view model of this control and add it to the list that is binding to the wrap pannel?
If this is not a good idea, how can I add items to the wrap pannel dynamically?
Thanks.
EDIT
I add code.
I am trying to do it but I don't get the solution.
I have a principal view model that create the view and the view model of my secondary view. In this principal view model I use this code:
ucDialogView myDialogView = new ucDialogView ();
ucDialogViewModel myDialogViewModel = new ucDialogViewModel ();
ucDialogView.DataContext = ucDialogViewModel;
The view model of my dialog is the following:
public class DialogViewModel : BaseViewModel
{
private ObservableCollection<ControlViewModel> _controls = new ObservableCollection<ControlViewModel>();
public ObservableCollection<ControlViewModel> Controls
{
get { return _myControls; }
set
{
_myControls = value;
base.RaisePropertyChangedEvent("Controls");
}
}
public myControlViewModel()
{
ControlViewModel myControlViewModel = new ControlViewModel();
Controls.Add(myControlViewModel);
}
}
My axml of my dialog:
<UserControl x:Class="MyApp.Views.DialogView"
Name="Principal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:my="clr-namespace:myApp.ViewModels"
mc:Ignorable="d"
d:DesignHeight="1122" d:DesignWidth="794" Width="794" Height="1122">
<ItemsControl Grid.Row="1"
ItemsSource="{Binding Controls, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel HorizontalAlignment="Center" Margin="0,15,0,0" Name="wrpControls" VerticalAlignment="Stretch" Width="Auto" Grid.Row="1" IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type my:ControlViewModel}">
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
However, I get an empty dialog. Control is a user control, a view and its view model.
I think a better approach might be to define a DataTemplate for each ViewModel type you want to use. Then, you can just add the ViewModel objects themselves to the WrapPanel's items.
The WPF infrastructure will see there is a DataTemplate for this type of object and will take care of showing the associated DataTemplate.
You need to declare the DataTemplate in some scope that is accessible to your WrapPanel, for example in the Resources of a parent page/window or in App.xaml's Resources:
<DataTemplate DataType="{x:Type local:YourViewModelClass}">
<ComboBox>
<!-- Define your bindings and stuff here -->
</ComboBox>
</DataTemplate>
Note that WrapPanel doesn't have an ItemsSource property, so if you want to bind its items to a list of objects (like your ViewModels), you'll need to use an ItemsControl:
<ItemsControl ItemsSource="{Binding YourListOfViewModels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Assuming YourListOfViewModels is an ObservableCollection of your ViewModels, each time you add a ViewModel to that list, it will be displayed with the correct DataTemplate.

WPF Binding To Child Control

I've got a TabControl which contains a nested ListView. The ListView is bound to the selected item in the parent TabControl. This works great in that switching tab displays the child elements in the ListView. What I can't figure out, is how to bind to the ListView's SelectedItem from outside of the Menu UserControl.
i.e.
<TabControl x:Name="Parent">
<TabControl.ContentTemplate>
<DataTemplate>
<ListView x:Name="Child"
ItemsSource="{Binding Path=SelectedItem.Tabs, ElementName=Parent}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
<ItemsControl ItemsSource="{Binding Path=SelectedItem.Controls, ElementName=Child}">
<ItemsControl.ItemTemplate>
<DataTemplate>
... controls go here ...
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I'm using M-V-VM so don't want to do my binding in code ideally - I'm sure it's possible, just can't figure it out :)
In general, if you need a property on a higher level you could move the property to the ViewModel that is bound to the higher level.
So, if I understand correctly, I would move the property of the ViewModel that is bound to the SelectedItem to the VM of the TabControl.
Does this make sense?

Binding to View Model Property from within ItemsControl.ItemTemplate

I have a collection of objects and a command in my ViewModel.
I want to display a hyperlink for each of the objects in the collection, and set the Command of each hyperlink to the same command, passing in the objectID as the CommandParemeter. e.g.
// View Model
public class MyViewModel : ViewModelBase
{
// Raises PropertyChanged event, ommited here
public List<MyClass> MyList {....}
public RelayCommand<int> MyCommand {....}
}
I set the DataContext of my UserControl to the above ViewModel class. The XAML for this UserControl is as follows:
<UserControl>
<ItemsControl ItemsSource="{Binding Path=MyList}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<HyperlinkButton Content="{Binding Path=Description}" Command="{Binding Path=MyCommand}" CommandParameter="{Binding Path=MyClassID}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
The Description for the Hyperlink content is shown correctly but the Command never fires, I guess this is because it's looking for a Command within the MyClass object?
How can I bind to the UserControls DataContext.MyCommand rather than the MyClass.MyCommand that it is looking for?
Unfortunately, we don't have the FindAncestor mode on the RelativeSource markup extension that WPF has, so you can't use that (this will be added in Silverlight 5). It's nasty, but you can give your UserControl element a name, and use ElementName binding to bind to the command on the object assigned to its DataContext.
For example:
<UserControl Name="root">
Then bind the command (using dot notation from the DataContext of the UserControl):
Command="{Binding Path=DataContext.MyCommand, ElementName=root}"
Give that a try.

Command Binding in UserControl used as ListBox.ItemTemplate

I have a Listbox with a UserControl as the DataTemplate. This UserControl has a Button to remove that item from the list.
<ListBox x:Name="FileList" ItemsSource="{Binding Files}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Views:FileItem/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The ItemsSource is defined as:
ObservableCollection<FileViewModel> m_fileViews = new ObservableCollection<FileViewModel>();
Here is the UserControl simplified:
<UserControl x:Class="Views.FileItem">
<Canvas x:Name="LayoutRoot">
<TextBlock x:Name="FileName" Text="{Binding FileName}" />
<Button Content="Remove"/>
</Canvas>
</UserControl>
When the user clicks the Remove button, it should remove this item from the ObservableCollection.
The problem is, the DataContext for each ListBoxItem is a different ViewModel than the ViewModel that holds the ObservableCollection.
I'm not sure how to bind the Remove button to an ICommand in the "parent" ViewModel. Any help would be appreciated. Thanks so much.
I would bind the button to an ICommand in the UserControl's ViewModel, then send a message across to the parent ViewModel using loosely-coupled messaging (available in most Mvvm frameworks, like MvvmFoundation)
Let the parent VM register for the 'remove me' message, and update the ObservableCollection accordingly...
Hope this helps :)

StackPanel not updating

I am having an issue with a directly bound ObservableCollection not updating a StackPanel when new items are added. Any initial items show up correctly. Only items that are added later on fail to display.
XAML:
<ItemsControl x:Name="ImageTable" ItemsSource="{Binding Path=SystemObjectViewItems, Converter={StaticResource UIElementWrapper}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<ContentPresenter Content="{Binding Path=Value.View}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I am using Prism MVVM so I am binding to my ViewModel which has a property:
public ObservableCollection<SystemObjectViewPresentationModel> SystemObjectViewItems {get; set; }
The basic converter and binding are working as can be demonstrated by the fact that my initial item displays correctly. It’s only items that are added to the collection after initial binding that do not show up.
Any ideas?
Thanks,
Rick
I'm going to take a wild guess and say it's the StaticResource you're using.
If you're not returning an ObservableCollection from it and you're not binding it to watch the original ObservableCollection changes it won't work.
Can you post the code to the converter?

Resources