WPF XAML data binding with dynamically resizing UserControl - c#

I have a UserControl with a grid containing text boxes. This object dynamically resizes itself with the text in the boxes. I need to bind the dimensions of this object to my model. Binding the 'Width' and 'Height' of the UserControl or Grid will break the dynamic resize, as the I am now stuck with whatever is the initial size declared in the model. I tried using 'minHeight' and 'minWidth' but these will not send data back to the model, as the minimum dimension never change. I have tried to fiddle with different modes(Oneway, ToWay etc..) but without luck.
So to sum up: I need a way to bind the dimensions while maintaining the dynamic resize with the text in the text boxes.
<UserControl x:Class="_02350Demo.View.ClassBoxUserControl"
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:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Canvas.Left="{Binding X}" Canvas.Top="{Binding Y}"
Width="{Binding Width}" Height="{Binding Height}">
<UserControl.InputBindings>
<KeyBinding Modifiers="Control" Key="Z" Command="{Binding UndoCommand}" />
<KeyBinding Modifiers="Control" Key="Y" Command="{Binding RedoCommand}" />
</UserControl.InputBindings>
<Grid>
<Rectangle Opacity="{Binding DataContext.ModeOpacity, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" StrokeThickness="6" StrokeDashArray="3.1">
<!-- The fill (background) color of the ellipse is a radial (center to edge) gradient (more than one color) brush. -->
<Rectangle.Fill>
<RadialGradientBrush>
<GradientStop Color="Black" Offset="0.0" />
</RadialGradientBrush>
</Rectangle.Fill>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<cmd:EventToCommand Command="{Binding DataContext.MouseDownShapeCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<cmd:EventToCommand Command="{Binding DataContext.MouseMoveShapeCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseUp">
<cmd:EventToCommand Command="{Binding DataContext.MouseUpShapeCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition />
</Grid.RowDefinitions>
<TextBox Text="{Binding ContentClass}" HorizontalAlignment="Stretch" AcceptsReturn="True" TextWrapping="Wrap" VerticalAlignment="Stretch" Grid.Row="0" BorderThickness="1,1,1,1" BorderBrush="Gray" TextAlignment="Center" Margin="30,0,30,0"/>
<TextBox Text="{Binding ContentFields}" HorizontalAlignment="Stretch" AcceptsReturn="True" TextWrapping="Wrap" VerticalAlignment="Stretch" Grid.Row="1" BorderThickness="1,1,1,1" BorderBrush="Gray"/>
<TextBox Text="{Binding ContentMethods}" HorizontalAlignment="Stretch" AcceptsReturn="True" TextWrapping="Wrap" VerticalAlignment="Stretch" Grid.Row="2" BorderThickness="1,1,1,1" BorderBrush="Gray"/>
</Grid>
</Grid>

If you simply want your view model to know about the dynamic size of the UserControl, you could handle the SizeChanged event of the UserControl and set the Width and Height source properties of your view model to the ActualWidth and ActualHeight properties of the UserControl respectively:
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
var vm = DataContext as YourViewModel;
vm.Height = ActualHeight;
vm.Width = ActualWidth;
}
You may wrap this in a behaviour if you want to: https://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF

Related

WPF - binding event to the ViewModel

I have a stack panel for which I need a mouse event to be handled in the ViewModel but the binding doesn't work - the command isn't found although the other elements are also binded to the ViewModel and they work. Here is the xaml:
<Window.DataContext>
<vm:Ticker/>
</Window.DataContext>
<ListView Grid.Row="3"
ItemsSource ="{Binding TickersCollectionView}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"
Name="STPListView">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction
Command="{Binding MouseLeftButtonDownCommand}"
CommandParameter="{Binding ElementName=STPListView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBlock
Width="130"
Text="{Binding Market}"
Foreground="WhiteSmoke"/>
<TextBlock
Width="110"
Text="{Binding Price}"
Foreground="{Binding LastPrice, Converter={StaticResource BoolToForeground}}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The command is a property of the ViewModel. How can I bind it?
If the MouseLeftButtonDownCommand property is defined in the same view model as the TickersCollectionView property, you should bind to it using a RelativeSource:
Command="{Binding DataContext.MouseLeftButtonDownCommand,
RelativeSource={RelativeSource AncestorType=ListView}}"

Replace a child element of a custom control in consuming code

I have a reusable custom control for search results. It uses ListView GridView to display the search results and it's already used in multiple places in my app.
<views:AbstractDictionaryPickerView x:Class="MyApp.Common.Controls.Dictionaries.Views.AbstractDictionaryPickerView"
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:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:watermark="clr-namespace:MyApp.Common.Controls.Watermark"
xmlns:behaviors="clr-namespace:MyApp.Common.Behaviors"
xmlns:listViewLayout="clr-namespace:Itenso.Windows.Controls.ListViewLayout;assembly=Itenso.Windows.Controls.ListViewLayout"
xmlns:views="clr-namespace:MyApp.Common.Controls.Dictionaries.Views"
xmlns:viewModels="clr-namespace:MyApp.Common.Controls.Dictionaries.ViewModels"
xmlns:design="clr-namespace:MyApp.Common.Controls.Dictionaries.ViewModels.Design"
d:DataContext="{design:DesignMultiDictionaryPickerViewModel}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Viewbox Stretch="Fill">
<Canvas Width="800" Height="800">
<Rectangle Fill="#ffffffff" Width="800" Height="800" />
<Rectangle Width="5" Height="800" >
<Rectangle.Fill>
<LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
<GradientStop Color="#FFCAEBF4"/>
<GradientStop Color="#FFCEF5FF" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Canvas>
</Viewbox>
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<TextBox
Grid.Row="0" Height="Auto"
Margin="5,0,5,0"
Style="{StaticResource TextBoxStyle}"
Text="{Binding SearchQuery, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Behaviors>
<watermark:TextBoxWatermarkBehavior Label="{Binding WatermarkText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
LabelStyle="{StaticResource WatermarkStyle}"/>
<behaviors:SelectAllWhenTextBoxFocusedBehavior/>
<behaviors:TextBoxArrowUpDownNavigationBehavior/>
<behaviors:SetLogicalFocusBehavior/>
</i:Interaction.Behaviors>
</TextBox>
<Grid Grid.Row="1">
<ListView listViewLayout:ListViewLayoutManager.Enabled="True" x:Name="SearchResultsList"
ItemsSource="{Binding FilteredElements}"
ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="5,2,5,3"
SelectionMode="Single"
>
<ListView.Resources>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextBlockStyle}"/>
</ListView.Resources>
<i:Interaction.Behaviors>
<behaviors:ArrowNavigationBehavior/>
<behaviors:AutoSizeListViewColumns/>
</i:Interaction.Behaviors>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDoubleClick">
<i:InvokeCommandAction Command="{Binding ChooseItemCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.InputBindings>
<KeyBinding Key="Enter"
Command="{Binding ChooseItemCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=SelectedItem}" />
<MouseBinding MouseAction="LeftDoubleClick"
Command="{Binding ChooseItemCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=SelectedItem}" />
</ListView.InputBindings>
<ListView.View>
<!-- GRIDVIEW TO REPLACE -->
<GridView ColumnHeaderContainerStyle="{StaticResource {x:Type GridViewColumnHeader}}" x:Name="ElementsGridView">
<GridViewColumn Header="">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="viewModels:ChoosableViewModel">
<CheckBox IsChecked="{Binding IsChosen}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Grid>
</Grid>
</views:AbstractDictionaryPickerView>
The consuming code looks like that:
<UserControl x:Class="MyApp.Modules.Management.OnlineRegistrationSettings.Tabs.AvailableDoctors.OnlineRegistrationDoctorsSettingsView"
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:views="clr-namespace:MyApp.Common.Controls.Dictionaries.Views;assembly=MyApp.Common"
xmlns:onlineRegistrationSettings="clr-namespace:MyApp.Modules.Management.OnlineRegistrationSettings"
d:DataContext="{d:DesignInstance onlineRegistrationSettings:OnlineRegistrationSettingsViewModel}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Style="{StaticResource LabelStyle}" Content="Wybór lekarzy, którzy mają być dostępni w rejestracji online."/>
<!-- HERE -->
<views:AbstractDictionaryPickerView DataContext="{Binding MultiDictionaryPickerViewModel}" Grid.Row="1"
Configuration="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}, Path=DataContext.Configuration}"/>
</Grid>
</UserControl>
Now I want do modify the GridView columns (add a new column with ComboBox).
Is it possible to override the GridView element of the views:AbstractDictionaryPickerView in the XAML of the consuming code? I mean what's below <!-- GRIDVIEW TO REPLACE --> tag in the first snippet.
Is it possible to override the GridView element of the views:AbstractDictionaryPickerView in the XAML of the consuming code?
No. At least not using only XAML.
But if you add a property to your AbstractDictionaryPickerView control that exposes the view of the ListView:
public partial class AbstractDictionaryPickerView : UserControl
{
public AbstractDictionaryPickerView()
{
InitializeComponent();
}
public ViewBase GridView
{
get { return SearchResultsList.View; }
set { SearchResultsList.View = value; }
}
}
...you could set the it to a new GridView in the consuming XAML markup:
<views:AbstractDictionaryPickerView>
<views:AbstractDictionaryPickerView.GridView>
<GridView>
<GridView.Columns>
<GridViewColumn Header="..." DisplayMemberBinding="{Binding}" />
</GridView.Columns>
</GridView>
</views:AbstractDictionaryPickerView.GridView>
</views:AbstractDictionaryPickerView>

How to handle selection event with a wrappanel

I'm currently on a C# WPF project and I display images in several rows (the blue heads)
The problem is that I can't select any of this items, I am using a MVVM pattern so the code behind must be as light as possible and I have to do eveything I can in the xaml file.
So I would like to be able to select images by clicking on them, I've tried to use event like "IsMouseOver" but I was only able to change the whole wrappanel and not single items.
Here is the code I use:
<Grid Grid.Row="1" Height="Auto">
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Color="#252525" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
<ItemsControl Background="Transparent" Foreground="AntiqueWhite" BorderBrush="Transparent"
HorizontalContentAlignment="Stretch" ItemsSource="{Binding Source={x:Static Context:Session.CurrentSession}, Path=CurrentProject.Models}">
<ItemsControl.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" Command="{Binding DeleteModel3DCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}"/>
</ContextMenu>
</ItemsControl.ContextMenu>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectModel3DCommand}" CommandParameter="{Binding Path=SelectedItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="/McKineap;component/Resources/Images/logo-mckineap.png" Height="100"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
I will take any suggestions you could have about the proper way to define a select event in my wrappanel, thanks for your time !
ItemsControl items wasn't meant to be selectable, that's why selection events and selection features are missing, more specifically ItemsControl doesn't inherit from Selector class which allow that, on the other hand ListBox and ListView do.
Change the ItemsControl to a ListView and you should be able to implement selection:
<ListView SelectionMode="Single" Background="Transparent" Foreground="AntiqueWhite" BorderBrush="Transparent"
HorizontalContentAlignment="Stretch" ItemsSource="{Binding Items}">
Edit
don't forget to disable the HorizontalScrollBar in the ListView in-order for the WrapPanel to work
<Grid Grid.Row="1" Height="Auto">
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Color="#252525" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
<ListView SelectionMode="Single" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Background="Transparent" Foreground="AntiqueWhite" BorderBrush="Transparent"
HorizontalContentAlignment="Stretch" ItemsSource="{Binding Items}">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" Command="{Binding DeleteModel3DCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}"/>
</ContextMenu>
</ListView.ContextMenu>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectModel3DCommand}" CommandParameter="{Binding Path=SelectedItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.ItemTemplate>
<DataTemplate>
<Image Source="refresh.png" Height="100"/>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</Grid>
I try to do the same way but with a ListBox instead of a ListView and it works for me.
<Grid Grid.Row="1" Height="Auto">
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Color="#252525" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
<ListBox Name="ModelsListBox" Background="Transparent" Foreground="AntiqueWhite" BorderBrush="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch" ItemsSource="{Binding Source={x:Static Context:Session.CurrentSession}, Path=CurrentProject.Models}">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" Command="{Binding DeleteModel3DCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}"/>
<MenuItem Header="Rename"/>
</ContextMenu>
</ListBox.ContextMenu>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectModel3DCommand}" CommandParameter="{Binding Path=SelectedItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,5,0" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Source="/McKineap;component/Resources/Images/logo-mckineap.png" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Bottom" Height="55" Width="50"/>
<ListBoxItem Grid.Column="1" Content="{Binding NameWithoutExtension}" HorizontalAlignment="Stretch" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>

How to access dynamic control WPF in DataTemplate

I created a tabcontrol with TabItem dynamic, and each TabItem with a button to close it, but just want that button visible when the TabItem is selected.
But I can not access the control inside the DataTemplate
<TabControl Name="dynamicTab" ItemsSource="{Binding}" Margin="0,85,0,0">
<TabControl.Resources>
<DataTemplate x:Key="TabHeader" DataType="TabItem">
<DockPanel>
<Button
Focusable="False"
BorderThickness="0"
Background="Transparent"
BorderBrush="Transparent"
Padding="-4"
Height="10"
Width="10"
Name="btnDelete" Visibility="Hidden" DockPanel.Dock="Right" Margin="5,0,0,0" Click="btnDelete_Click"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Name}">
<Image Name="imgButtonClose" Source="/Recursos;component/Imagens/close16x16.png" Height="10" Width="10"/>
</Button>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Header}" />
</DockPanel>
</DataTemplate>
</TabControl.Resources>
</TabControl>
Just use the binding on the IsSelected property of ancestoral TabItem:
<BooleanToVisibilityConverter x:Key="boolToVisibilityConverter"/>
...
<Button ...
Name="btnDelete"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=IsSelected, Converter={StaticResource boolToVisibilityConverter}">
...
</Button>
If you have no problems with this binding:
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Name}"
then the proposed code should work.

Is there anyway of consolidating similar data bindings and/or triggers in XAML?

I have a user control that hosts other controls. The way I implemented this is via data templates that define the control that should be associated with a specific view-model. These view-models have similar properties and interaction triggers. Please see XAML snippet below.
The problem with this approach is that I would have to copy-paste the data bindings if I want to support a new view-model. Is there any way of consolidating all similar data bindings and/or triggers into one template? I don't want to type/copy-paste the same data binding definitions into each control. (Yes, I know, I'm that lazy.)
<UserControl.Resources>
<DataTemplate DataType="{x:Type vm:SomeViewModel1}">
<TextBlock Canvas.Left="{Binding Left}"
Canvas.Top="{Binding Top}"
RenderTransform="{Binding Transform}"
Height="{Binding Height}"
Width="{Binding Width}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<cmd:EventToCommand Command="{Binding MouseEnterCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<cmd:EventToCommand Command="{Binding MouseLeaveCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SomeViewModel2}">
<Rectangle Canvas.Left="{Binding Left}"
Canvas.Top="{Binding Top}"
RenderTransform="{Binding Transform}"
Height="{Binding Height}"
Width="{Binding Width}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<cmd:EventToCommand Command="{Binding MouseEnterCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<cmd:EventToCommand Command="{Binding MouseLeaveCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SomeViewModel3}">
<Button Canvas.Left="{Binding Left}"
Canvas.Top="{Binding Top}"
RenderTransform="{Binding Transform}"
Height="{Binding Height}"
Width="{Binding Width}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<cmd:EventToCommand Command="{Binding MouseEnterCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<cmd:EventToCommand Command="{Binding MouseLeaveCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SomeViewModel4}">
<!-- Do not want copy-paste code here... -->
</DataTemplate>
</UserControl.Resources>
You can use common style, and put both your properties and triggers (which are also properties) inside this style, look at this StackOverflow question
for more details.
What about putting the triggers into a resource and associating them with your controls. Or use a custom base class for your DataTemplates.

Categories