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)
Related
I have
three WPF UserControls with their Viewmodels
one WPF container for displaying one of the WPF Usercontrols
WinForm Usercontrol
I want: display different WPF UserControl, which I set is in WinForms User Control
public partial class WinContainer : UserControl
{
public WinContainer()
{
InitializeComponent();
WPFContainer WPFControl = new WPFContainer();
PartPageViewModel ss = new PartPageViewModel();
WPFControl.DataContext = ss;
ElementHost elHost = new ElementHost();
elHost.Child = WPFControl;
elHost.Dock = DockStyle.Fill;
this.Controls.Add(elHost);
}
}
<UserControl x:Class="MDMSpecification.Views.WPFContainer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MDMSpecification.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:services="clr-namespace:MDMSpecification.Services"
xmlns:viewModels="clr-namespace:MDMSpecification.ViewModels"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<UserControl.Resources>
<DataTemplate x:Key="Assembly" DataType="{x:Type viewModels:AssemblyPageViewModel}">
<local:AssemblyPageView />
</DataTemplate>
<DataTemplate x:Key="Part" DataType="{x:Type viewModels:PartPageViewModel}">
<local:PartPageView />
</DataTemplate>
<DataTemplate x:Key="Drawing" DataType="{x:Type viewModels:DrawingPageViewModel}">
<local:DrawingPageView />
</DataTemplate>
</UserControl.Resources>
<StackPanel>
<ContentPresenter Content="{Binding}" />
</StackPanel>
</UserControl>
In result I have this:
What's wrong with my code?
Remove x:Key="XYZ" from DataTemplate.
In order to apply a DataTemplate automatically to DataType you should omit the key.
For example:
<DataTemplate DataType="{x:Type viewModels:AssemblyPageViewModel}">
<local:AssemblyPageView />
</DataTemplate>
This xaml is equivalent to:
<DataTemplate x:Key={x:Type viewModels:AssemblyPageViewModel}
DataType="{x:Type viewModels:AssemblyPageViewModel}">
<local:AssemblyPageView />
</DataTemplate>
DataTemplates with a key should be applied explicitly like this:
<ContentPresenter Content="{Binding}" ContentTemplate="{StaticResource Assembly}" />
I have a HeaderedContentControl in my application. In this HeaderedContentControl there is a TabControl.
Now I want to display the name of the selected tab (TabItem) in the header of the HeaderedContentControl (like in Visual Studio the Solution Explorer / Team Explorer e.g.).
My application is (partly) based on Josh Smiths WPF-MVVM-Example but I use additional Prism with Unity.
Furthermore I split the resources in some files.
Here is my MainView.xaml:
<UserControl x:Class="STController.ModuleAComport.View.MainView"
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"
d:DesignHeight="300"
d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="..\Resources\MainViewResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.Resources>
</Grid.Resources>
<Border Grid.Row="0"
Grid.Column="0"
Style="{StaticResource MainBorderStyle}">
<HeaderedContentControl Header="?"
Style="{StaticResource MainHeadreredContentControlStyle}"
ContentTemplate="{StaticResource WorkspacesTemplate}"
Content="{Binding Path=Workspaces}" />
</Border>
</Grid>
</UserControl>
And here is my MainViewResources.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:STController.ModuleAComport.View"
xmlns:viewmodel="clr-namespace:STController.ModuleAComport.ViewModel">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/STController.Resources;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Put your not shared resource here -->
<DataTemplate DataType="{x:Type viewmodel:ComportViewModel}">
<view:ComportView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodel:TestViewModel}">
<view:TestView />
</DataTemplate>
<DataTemplate x:Key="TabItemTemplate">
<Grid>
<ContentPresenter VerticalAlignment="Center"
Content="{Binding Path=DisplayName}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl x:Name="TabControl"
IsSynchronizedWithCurrentItem="True"
TabStripPlacement="Bottom"
Style="{StaticResource MainTabControlStyle}"
ItemsSource="{Binding}"
Margin="4"
ItemTemplate="{StaticResource TabItemTemplate}"
ItemContainerStyle="{StaticResource MainTabItemStyle}">
</TabControl>
</DataTemplate>
</ResourceDictionary>
I had two different solution approaches:
1) Binding the SelectedIndex:
My first idea was to bind the SelectedIndex of the TabControl to a property in my viewmodel.
With the index I can then "select" the related view (viewmodel) and get the name and bind it to the header (see HeaderedContentControl; Content="{Binding Path=Workspaces}"; Workspaces is of type ObservableCollection)
But once I bind the SelectedIndex property of the TabControl, the TabControl does not switch reliable anymore. Sometimes when I click on the TabItem it is switching sometimes not. Sometimes I need to click ten or more times. A very strange behavior. There is no difference if I implement the property (SelectedIndex) in my viewmodel or not.
2) Elementbinding:
My second idea was to implement a ElementName-Binding
But as I expected this does not work (Visual / Logical Tree). The error is:
"Cannot find source for binding with reference 'ElementName=TabControl'.
BindingExpression:Path=ActualHeight; DataItem=null; target element is
'HeaderedContentControl' (Name=''); target property is 'Header' (type
'Object')"
In this case I also tried to move the TabControl into the Resources of the UserControl and Grid.
So the question is: Is it possible / how is it possible to show the name of the selected tab of the TabControl in the header of the HeaderedContentControl?
Is there a solution without code behind (I don't really like code behind ;) )?
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>
so i had the same problem as this person.. WPF: Bind Collection with Collection to a ListBox with groups
I tried to implement the suggested answer to my problem but found the error "The property 'Content' is set more than once". The only difference is id like to implement this in a User Control like so:
here is my c# code:
public class Dog
{
public int dogID { get; set; }
public String Name { get; set; }
List<Puppy> puppies { get; set; }
}
public class Puppy
{
public String Name { get; set; }
}
and this is XAML:
<UserControl x:Class="PetStore.Menu"
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"
d:DesignHeight="300" d:DesignWidth="300">
<CollectionViewSource x:Name="dogs" Source="{Binding}" >
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Name" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<DataTemplate x:Key="dogTemplate" DataType="Project">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
<ListBox ItemsSource="{Binding Source={StaticResource dogs}}">
<ListBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource dogTemplate}" />
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="Puppy">
<ListBox ItemsSource="{Binding puppies}">
<ListBox.ItemTemplate>
<DataTemplate DataType="Puppy">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
Any help is greatly appreciated!!
You're missing the UserControl.Resources tag:
<UserControl x:Class="Tackle.View.Menu"
...>
<UserControl.Resources> <!-- You're missing this -->
<CollectionViewSource x:Key="dogs" Source="{Binding}" > <!-- Change x:Name to x:Key here -->
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Name" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<DataTemplate x:Key="dogTemplate" DataType="Project">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<!-- here goes your window content -->
The error message tells you what you did wrong: you attempted to set the Content property more than once. When you declare an element as a direct child of a control, then you are implicitly setting whichever property is specified in the [ContentProperty("...")] attribute on that control type. For ContentControl (and its subclass UserControl), that property is Content. If you want to set a different property, or add something to a collection/dictionary property, you must specify the property name. This means either using the Property="value" attribute syntax or the <Owner.Property> element syntax.
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!