Multiple usercontrol not reflected while setting DataTemplate to ViewModel in MVVM - c#

I am trying to add two usercontrols in one view
usercontrol working fine which get call in constructor i am implementing INotifyPropertyChanged for 'SelectedViewModel'.
property get updated for second usercontrol but not reflected in view .
thanks in advance
<Window x:Class="MovieBookinGWithUserControl.View.StartupWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MovieBookinGWithUserControl.ViewModel"
xmlns:localview ="clr-namespace:MovieBookinGWithUserControl.View"
Title="StartupWindow" Height="AUTo" Width="Auto">
<Window.Resources>
<DataTemplate DataType="{x:Type local:LoginWIndowViewModel}">
<localview:LoginWindow></localview:LoginWindow>
</DataTemplate>
<DataTemplate DataType="{x:Type local:MovieInfoViewModel }">
<localview:MovieInfo ></localview:MovieInfo>
</DataTemplate>
</Window.Resources>
<Grid>
<DockPanel LastChildFill="True">
<StackPanel x:Name="navigation" DockPanel.Dock="Left" Width="Auto">
</StackPanel>
<ContentControl x:Name="Pages" DockPanel.Dock="Right" Content="{Binding SelectedViewModel,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</DockPanel>
</Grid>
</Window>

Related

WPF UserControl not rendering. UserControl is instantiated using DataTemplates

I have a user control that I`m trying to show via data templates. Unfortunately, the control never shows. Here's the DataTemplate for it:
<DataTemplate x:Key="listViewTemplate">
<ctrls:SpecialControl/>
</DataTemplate>
If I put regular controls inside those DataTemplate tags, I can see them. My SpecialControl however, won't show. Here's the xaml file for my SpecialControl:
<UserControl x:Class="CustomControls.SpecialControl"
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"
mc:Ignorable="d">
<StackPanel>
<CheckBox Content="Hello World" />
<Button >
<TextBlock Text="Goodbye world"/>
</Button>
</StackPanel>
</UserControl>
For some reason, this control is invisible at run time. If I put them directly into the template, I'll see them. I know I could just do that, but I want to do something more complex with this class, using databinding, and custom behavior. I tried using Snoop, and I can see my SpecialControl in there somewhere, with a ContentPresenter that's not expandable: no sign of The checkbox or the button.
Edit:
Here is the View that is using the SpecialControl: I left out many of the templates I'm using, because I don't want this to be too crowded.
<UserControl x:Class="Tools.EditorWindow"
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:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
xmlns:ctrls="clr-namespace:CustomControls"
xmlns:local="clr-namespace:Tools"
mc:Ignorable="d"
x:Name="This">
<UserControl.Resources>
<!--More templates -->
<DataTemplate x:Key="groupBoxTemplate" >
<ctrls:SpecialGroupBox Header="{Binding Path=Title}" Margin="2" DockPanel.Dock="Top">
<ItemsControl ItemsSource="{Binding guiItemsList}" ItemTemplateSelector="{DynamicResource guiTemplateSelector}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel>
<!-- Set up the width of the individual items based on how many columns we are supposed to have and what the adjusted width of the wrapPanel is. This way the 4th item will be placed on the 2nd row if the ColumnCount is 3. -->
<WrapPanel.ItemWidth>
<MultiBinding Converter="{StaticResource itemWidthConverter}">
<Binding Path="ColumnCount"/>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</WrapPanel.ItemWidth>
</WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ctrls:SpecialGroupBox>
</DataTemplate>
<DataTemplate x:Key="listViewTemplate">
<ctrls:SpecialControl/>
</DataTemplate>
<local:GuiTemplateSelector
... <!--More templates -->
GroupBoxTemplate="{StaticResource groupBoxTemplate}"
SpecialTemplate="{StaticResource listViewTemplate}"
x:Key="guiTemplateSelector"/>
</UserControl.Resources>
<DockPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Row="1">
<StackPanel Name="rootPanel" DockPanel.Dock ="Top" Width="Auto" Height="Auto">
<ItemsControl ItemsSource="{Binding guiItemsList}" ItemTemplateSelector=" {StaticResource guiTemplateSelector}">
</ItemsControl>
</StackPanel>
</ScrollViewer>
</DockPanel>
</UserControl>
If you're wondering what the SpecialGroupBox does, it holds other controls, positioning them a certain way. There are a few of them in this window, and they work. It is inside of one of these SpecialGroupBoxes that my SpecialControl is supposed to appear.
Does your UserControl have a corresponding .xaml.cs file? This problem seems to happen when it doesn't.
If you're using Visual Studio, try copying all the XAML from your UserControl, then deleting it from your project, adding a new UserControl (with the same name as before), then pasting your content back into the XAML file. This will ensure that you have the correct .xaml.cs file set up.
See this answer.
In your post you didn't mention how you are using the listViewTemplate . if your using inside listview/listbox you can try like this it will load the user control:
<ListView ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate >
<ContentControl ContentTemplate="{StaticResource listviewDataTemplate}" Content="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Updating data binding source of a content control in a ResourceDictionary

I want to create a view that has a set of tabs (each, basically a ContentControl) that each have various settings. I then want to have a button that will update all of the data binding rather than updating instantly or having update buttons associated with the controls themselves
So, my control is MEF exported as a ResourceDictionary and is similar to the below
<ResourceDictionary ...>
<DataTemplate DataType="{x:Type vm:AdminViewModel}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TabControl Grid.Row="0">
<TabItem Header="Tests">
<ContentControl Content="{Binding ResultStorage}"/>
</TabItem>
</TabControl>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button Content="Update"/>
<Button Content="Cancel"/>
</StackPanel>
</Grid>
</DataTemplate>
</ResourceDictionary>
TestStorage would be like this:
<ResourceDictionary ...>
<DataTemplate DataType="{x:Type data:XmlResultStorage}">
<StackPanel>
<TextBlock Text="Result File Path:"/>
<TextBox Text="{Binding Path=ResultPath, Source={x:Static properties:DataStorage.Default}, UpdateSourceTrigger=Explicit}"/>
<TextBlock Text="Result File Location:"/>
<TextBox Text="{Binding Path=ResultFilename, Source={x:Static properties:DataStorage.Default}, UpdateSourceTrigger=Explicit}"/>
</StackPanel>
</DataTemplate>
What I want to do is when the button to update is pressed to somehow call the update (UpdateSource?) on the ContentControl but I can't see how to do it.
In an ideal world I wouldn't have code-behind and do it all via MVVM or something, but if that's not possible code-behind is fine.
So I have two issues, how do I update data bindings manually via a ResourceDictionary and how do I then cause it to cascade through its child ContentControls?

DataTemplate not drawing the View, but printing the typename for each ViewModel type it encounters in a Collection

<Grid>
<ItemsControl ItemsSource="{Binding ScreenViewModelCollection}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type redScreenView:RedScreenView}">
<Grid>
<redScreenView:RedScreenView/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type greenScreenView:GreenScreenView}">
<Grid>
<greenScreenView:GreenScreenView/>
</Grid>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
Instead of drawing the View for its ViewModel, it prints the namespace that the View belongs to!
But using an ItemTemplate works for just one of them. And ItemTemplate can't have more than one content :(
Your DataTemplates are for Views while I suspect your ScreenViewModelCollection contains ViewModels.
You just need to make the DataType properties be ViewModels instead of Views
<DataTemplate DataType="{x:Type myViewModels:RedScreenViewModel}">
<Grid>
<redScreenView:RedScreenView/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type myViewModels:GreenScreenViewModel}">
<Grid>
<greenScreenView:GreenScreenView/>
</Grid>
</DataTemplate>
i miss the definition for redScreenView/greenScreenView namespace, type of ScreenViewModelCollection, xaml for ItemsControl.ItemTemplate - so i just assume:
EDIT: pls look at your xaml i think you has some typos in there. the DataType for your DataTemplates should be the viewmodel. the content of the datatemplate the view of course.
nevertheless the local define the namespace and have to be in your window/usercontrol definition. e.g.
<UserControl xmlns:local="clr-namespace:MyWpfApplication1.MyTest.ViewModels"
xmlns:views="clr-namespace:MyWpfApplication1.Controls.Views"
<ItemsControl ItemsSource="{Binding ScreenViewModelCollection}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:RedScreenViewModel}">
<Grid>
<views:RedScreenView/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:GreenScreenViewModel}">
<Grid>
<views:GreenScreenView/>
</Grid>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
does this ItemTemplate work for you?

Caliburn Micro: UserControl Binding

I use Caliburn Micro for my WPF application. I implemented a little UserControl:
<UserControl Name="ImageButtonUserControl"
x:Class="SportyMate.Utility.Controls.ImageButton"
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">
<Grid>
<Button>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ElementName=ImageButtonUserControl, Path=Image}" />
<TextBlock Text="{Binding ElementName=ImageButtonUserControl, Path=Text}" />
</StackPanel>
</Button>
</Grid>
</UserControl>
Now I want to use these Control in my view:
<uc:ImageButton Name="Cancel" Image="/Images/Icons/cancel_16x16.png" Text="Abbrechen" Margin="3" />
When I want to open my view (in my case it's opened as a dialog) it doesn't work. The View does not openend.
When I remove the Name-Attribute everthing is fine, but the Button have no binding to an action. Can anyone tell me what I have to do for a correct binding? A regular Button worked.
You are on a completely wrong way. You shouldn't create a user control for such a simple modification. You need to create a DataTemplate and use it for a Button.ContentTemplate. First you need to define a helper type for button content:
public class ImageButtonContent
{
public BitmapImage Image { get; set; }
public string Label { get; set; }
}
After that you can use it for DataTemplate:
<Window x:Class="Trys.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Trys="clr-namespace:Trys"
Title="MainWindow"
Height="350"
Width="525">
<Window.Resources>
<Trys:ImageButtonContent x:Key="YourImageButtonHere"
Label="Your ImageButtonHere">
<Trys:ImageButtonContent.Image>
<BitmapImage UriSource="your-icon.png" />
</Trys:ImageButtonContent.Image>
</Trys:ImageButtonContent>
<DataTemplate x:Key="ImageButton"
DataType="{x:Type Trys:ImageButtonContent}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}"
Margin="5" />
<TextBlock Text="{Binding Label}"
VerticalAlignment="Center"
Margin="10,0,0,0" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Button ContentTemplate="{StaticResource ImageButton}"
Content="{StaticResource YourImageButtonHere}"
Height="50"
Width="250" />
</Grid>
</Window>
I used a resource for an object, but you can use a property on your ViewModel. The result is:
And this just a normal button. You can use for it all power of Caliburn.Micro conventions like Click event default binding. Enjoy!

Contentcontrol doesn't find my datatemplate it's ViewModel

I'm using WPF, MVVM & PRISM.
I got a datatemplate in my View linked to a ViewModel UC2002_RFPBeheren_ViewModel cause the page were this code is included is linked to another ViewModel and I want the Button to have UC2002_RFPBeheren_ViewModel as ViewModel.
The datacontext of this page is UC2002_RFPBeheren_ProjectInfo_ViewModel but I want the SaveButton to use the ViewModel UC2002_RFPBeheren_ViewModel
Here is my code:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources/RFPModuleResources.xaml" />
<ResourceDictionary>
<DataTemplate x:Key="SaveButton" DataType="{x:Type vm:UC2002_RFPBeheren_ViewModel}">
<Button Command="{Binding SaveRFPCommand}">Save</Button>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<ContentControl ContentTemplate="{StaticResource SaveButton}"/>
<Button Command="{Binding CloseTabCommand}">Close</Button>
</StackPanel>
Although the SaveButton displays but don't reacts on my command.
Do I forget something or is there another way to solve this?
Thanks in advance ;) !
=================================================================================
EDIT:
So I made some changes but it still doesn't work.
Code example:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources/RFPModuleResources.xaml" />
<ResourceDictionary>
<DataTemplate x:Key="SaveButton" DataType="{x:Type vm:UC2002_RFPBeheren_ViewModel}">
<Button Command="{Binding SaveRFPCommand}">Save</Button>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
I set this property in the ViewModel of the page
public UC2002_RFPBeheren_ViewModel MySaveVM { get; set; }
My stackpanel looks now like this:
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<ContentControl Content="{Binding MySaveVM}" ContentTemplate="{StaticResource SaveButton}"/>
<Button Command="{Binding CloseTabCommand}">Close</Button>
</StackPanel>
what happens if you set your UV2002_RFPBeheren_ViewModel instance as the content for the ContentPresenter?
<ContentControl Content="{Binding MyUV2002_RFPBeheren_ViewModel}"/>
the DataTemplate just say how your Viewmodel should be displayed, but you have to set the DataContext or Binding to the instance of your viewmodel.
EDIT:
example
public class VMFoo
{
public UV2002_RFPBeheren_ViewModel MySaveVM {get; set;}
}
xaml
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources/RFPModuleResources.xaml" />
<ResourceDictionary>
<DataTemplate x:Key="SaveButton" DataType="{x:Type vm:UC2002_RFPBeheren_ViewModel}">
<Button Command="{Binding SaveRFPCommand}">Save</Button>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.DataContext>
<x:local VMFoo/>
</UserControl.DataContext>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<ContentControl Content="{Binding MySaveVM}"/>
<Button Command="{Binding CloseTabCommand}">Close</Button>
</StackPanel>
EDIT: Small working sample
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplication1="clr-namespace:WpfApplication1" Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type WpfApplication1:UV2002_RFPBeheren_ViewModel}">
<Button Command="{Binding SaveRFPCommand}">Save</Button>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.DataContext>
<WpfApplication1:VMFoo/>
</Grid.DataContext>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<ContentControl Content="{Binding MySaveVM}"/>
<Button Command="{Binding CloseTabCommand}">Close</Button>
</StackPanel>
</Grid>
</Window>
Viewmodels
public class VMFoo
{
public VMFoo()
{
this.MySaveVM = new UV2002_RFPBeheren_ViewModel();
}
public UV2002_RFPBeheren_ViewModel MySaveVM { get; set; }
}
public class UV2002_RFPBeheren_ViewModel
{
private DelegateCommand _save;
public ICommand SaveRFPCommand
{
get{if(this._save==null)
{
this._save = new DelegateCommand(()=>MessageBox.Show("success"),()=>true);
}
return this._save;
}
}
}
This is because of the way that ContentControl's work. It is assumed that the things in the ContentTemplate are related to the Content and so the DataContext is set to the Content and therefore that is the DataContext that the button within the template has access to. You haven't specified a Content so the value is null and so the DataContext is explicitly set to null. You can see this in a basic example. One thing you can do is to bind the Content of the ContentControl to the DataContext - see the last contentcontrol in the example.
<StackPanel DataContext="Foo">
<StackPanel.Resources>
<DataTemplate x:Key="withBtn">
<Button Content="{Binding}" />
</DataTemplate>
</StackPanel.Resources>
<Button Content="{Binding}" />
<ContentControl ContentTemplate="{StaticResource withBtn}" />
<ContentControl Content="{Binding}" ContentTemplate="{StaticResource withBtn}" />
</StackPanel>
If you are using MVVM you must expose some instance of UC2002_RFPBeheren_ViewModel within your UC2002_RFPBeheren_ProjectInfo_ViewModel to bind against. Either as a property, or an item of a collection that is a property.
Everything in the view must be ultimately accessible from the ViewModel that is your data context (UC2002_RFPBeheren_ProjectInfo_ViewModel)

Categories

Resources