Although this post is called Scale Transform Behaviour you could use any transform / animation in its place. The purpose is to have a slider control in a menu be able to alter the scale of any number of controls within MVVM views.
This behaviour allows you to add any Framework Elements to a list of attached controls by adding an attached property of GlobalScaleTransformBehaviour.IsScaled to your controls.
1Public Class GlobalScaleTransformBehaviour
2
3 Private Shared sm_AttachedControls As List(Of FrameworkElement)
4 Public Shared ReadOnly IsScaledProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsScaled", GetType(Boolean), GetType(GlobalScaleTransformBehaviour), New UIPropertyMetadata(False, New PropertyChangedCallback(AddressOf GlobalScaleTransformBehaviour.IsScaledChanged)))
5 Private Shared sm_CurrentScale As Double = 1
6
7 Shared Sub New()
8 sm_AttachedControls = New List(Of FrameworkElement)
9 End Sub
10
11 Public Shared Function GetIsScaled(ByVal element As DependencyObject) As Boolean
12 If element Is Nothing Then
13 Throw New ArgumentNullException("element")
14 End If
15
16 Return element.GetValue(IsScaledProperty)
17 End Function
18
19 Public Shared Sub SetIsScaled(ByVal element As DependencyObject, ByVal value As Boolean)
20 If element Is Nothing Then
21 Throw New ArgumentNullException("element")
22 End If
23 element.SetValue(IsScaledProperty, value)
24 End Sub
25
26 Private Shared Sub IsScaledChanged(ByVal obj As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
27 Dim itemToResize As FrameworkElement = TryCast(obj, FrameworkElement)
28 If (Not itemToResize Is Nothing) Then
29 If Object.Equals(e.NewValue, True) Then
30 sm_AttachedControls.Add(itemToResize)
31 itemToResize.LayoutTransform = New ScaleTransform(sm_CurrentScale, sm_CurrentScale)
32 Else
33 sm_AttachedControls.Remove(itemToResize)
34 itemToResize.LayoutTransform = New ScaleTransform(1, 1)
35 End If
36 End If
37 End Sub
38
39End Class
As you can see, there is an attached dependency Boolean property defined with a PropertyChangedCallback. When the PropertyChangedCallback method is called we test to see if it is a True or False value and either add the control to a static list and set the current Transform, or remove the control from the list and reset the transform to 1.
This works grate and you can manipulate the list of controls at runtime by changing the dependency property.
1<igWindows:TabItemEx
2 xmlns:igDP="http://infragistics.com/DataPresenter"
3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4 xmlns:local="clr-namespace:Hinshlabs.WpfHeatItsmDashboard"
5 xmlns:igWindows="http://infragistics.com/Windows"
6 xmlns:igDock="http://infragistics.com/DockManager"
7 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
8 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
9 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
10 xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
11 mc:Ignorable="d"
12 xmlns:igEditors="http://infragistics.com/Editors"
13 xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
14 xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
15 x:Class="CallsView" x:Name="CallsView" MinWidth="30" MinHeight="50">
16 <igWindows:TabItemEx.Resources>
17 <local:NinjectDataProvider
18 x:Key="ViewModel"
19 d:IsDataSource="True" ObjectType="{x:Type local:CallsViewModel}"
20 />
21 <local:DateTimeSecondsToBooleanConverter x:Key="DateTimeSecondsToBooleanConverter" />
22 </igWindows:TabItemEx.Resources>
23 <igWindows:TabItemEx.Triggers>
24 <EventTrigger RoutedEvent="FrameworkElement.Loaded"/>
25 </igWindows:TabItemEx.Triggers>
26 <igWindows:TabItemEx.Header>
27 <igEditors:XamTextEditor Text="{Binding Source={StaticResource ViewModel},Path=Header, diag:PresentationTraceSources.TraceLevel=High}" />
28 </igWindows:TabItemEx.Header>
29
30 <DockPanel local:GlobalScaleTransformBehaviour.IsScaled="True" DataContext="{Binding Source={StaticResource ViewModel}}">
31 <Border DockPanel.Dock="Top" Background="LightGray" MinHeight="20">
32 <Border.Style>
33 <Style>
34 <Style.Triggers>
35 <DataTrigger Binding="{Binding Source={StaticResource ViewModel},Path=IsLoading, diag:PresentationTraceSources.TraceLevel=High}" Value="False">
36 <Setter Property="Border.Visibility" Value="Collapsed" />
37 </DataTrigger>
38 </Style.Triggers>
39 </Style>
40 </Border.Style>
41 <Label Content="Loading data..." />
42 </Border>
43 <Border DockPanel.Dock="Top" Background="LightGray" MinHeight="20">
44 <Border.Style>
45 <Style>
46 <Style.Triggers>
47 <DataTrigger Binding="{Binding Source={StaticResource ViewModel},Path=IsSyncing, diag:PresentationTraceSources.TraceLevel=High}" Value="False">
48 <Setter Property="Border.Visibility" Value="Collapsed" />
49 </DataTrigger>
50 </Style.Triggers>
51 </Style>
52 </Border.Style>
53 <Label Content="Syncing data..." />
54 </Border>
55 <igDP:XamDataGrid DataSource="{Binding Calls}" Theme="Office2k7Blue">
56 <igDP:XamDataGrid.Resources>
57 <Style x:Key="{x:Type igDP:DataRecordCellArea}" TargetType="{x:Type igDP:DataRecordCellArea}">
58 <Style.Triggers>
59 <DataTrigger Binding="{Binding DataItem.TypeOfCall, Converter={StaticResource DateTimeSecondsToBooleanConverter}, ConverterParameter=1}" Value="True">
60 <Setter Property="Background">
61 <Setter.Value>
62 <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
63 <LinearGradientBrush.GradientStops>
64 <GradientStopCollection>
65 <GradientStop Offset="0" Color="Red"/>
66 <GradientStop Offset="1" Color="Green"/>
67 </GradientStopCollection>
68 </LinearGradientBrush.GradientStops>
69 </LinearGradientBrush>
70 </Setter.Value>
71 </Setter>
72 </DataTrigger>
73 </Style.Triggers>
74 </Style>
75 </igDP:XamDataGrid.Resources>
76 <igDP:XamDataGrid.FieldSettings>
77 <igDP:FieldSettings AllowRecordFiltering="true" FilterEvaluationTrigger="OnCellValueChange" AllowSummaries="True" FilterOperatorDropDownItems="All" />
78 </igDP:XamDataGrid.FieldSettings>
79 <igDP:XamDataGrid.FieldLayoutSettings>
80 <igDP:FieldLayoutSettings AutoGenerateFields="true" FilterUIType="LabelIcons" />
81 </igDP:XamDataGrid.FieldLayoutSettings>
82 </igDP:XamDataGrid>
83 </DockPanel>
84</igWindows:TabItemEx>
There is quite a lot of Wpf here, so I have highlighted the DockPanel to which the dependency has been applied. All we now need to do is provide a way to manipulate this value. We need to add a ScaleValue attached dependency property to our Behaviour that we can bind to our single or set of control controls.
1Public Class GlobalScaleTransformBehaviour
2
3 Private Shared sm_AttachedControls As List(Of FrameworkElement)
4 Public Shared ReadOnly IsScaledProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsScaled", GetType(Boolean), GetType(GlobalScaleTransformBehaviour), New UIPropertyMetadata(False, New PropertyChangedCallback(AddressOf GlobalScaleTransformBehaviour.IsScaledChanged)))
5 Public Shared ReadOnly ScaleValueProperty As DependencyProperty = DependencyProperty.RegisterAttached("ScaleValue", GetType(Double), GetType(GlobalScaleTransformBehaviour), New UIPropertyMetadata(CType(1, Double), New PropertyChangedCallback(AddressOf GlobalScaleTransformBehaviour.ScaleValueChanged)))
6 Private Shared sm_CurrentScale As Double = 1
7
8 Shared Sub New()
9 sm_AttachedControls = New List(Of FrameworkElement)
10 End Sub
11
12 Public Shared Function GetIsScaled(ByVal element As DependencyObject) As Boolean
13 If element Is Nothing Then
14 Throw New ArgumentNullException("element")
15 End If
16
17 Return element.GetValue(IsScaledProperty)
18 End Function
19
20 Public Shared Sub SetIsScaled(ByVal element As DependencyObject, ByVal value As Boolean)
21 If element Is Nothing Then
22 Throw New ArgumentNullException("element")
23 End If
24 element.SetValue(IsScaledProperty, value)
25 End Sub
26
27 Private Shared Sub IsScaledChanged(ByVal obj As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
28 Dim itemToResize As FrameworkElement = TryCast(obj, FrameworkElement)
29 If (Not itemToResize Is Nothing) Then
30 If Object.Equals(e.NewValue, True) Then
31 sm_AttachedControls.Add(itemToResize)
32 itemToResize.LayoutTransform = New ScaleTransform(sm_CurrentScale, sm_CurrentScale)
33 Else
34 sm_AttachedControls.Remove(itemToResize)
35 itemToResize.LayoutTransform = New ScaleTransform(1, 1)
36 End If
37 End If
38 End Sub
39
40 Public Shared Function GetScaleValue(ByVal element As DependencyObject) As Double
41 If element Is Nothing Then
42 Throw New ArgumentNullException("element")
43 End If
44
45 Return element.GetValue(ScaleValueProperty)
46 End Function
47
48 Public Shared Sub SetScaleValue(ByVal element As DependencyObject, ByVal value As Double)
49 If element Is Nothing Then
50 Throw New ArgumentNullException("element")
51 End If
52 element.SetValue(ScaleValueProperty, value)
53 End Sub
54
55 Private Shared Sub ScaleValueChanged(ByVal obj As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
56 If Not Application.Current.Dispatcher.CheckAccess Then
57 Exit Sub
58 End If
59 sm_CurrentScale = e.NewValue
60 SyncLock sm_AttachedControls
61 For Each itemToResize In sm_AttachedControls.ToList
62 ' Apply Tensform
63 itemToResize.LayoutTransform = New ScaleTransform(sm_CurrentScale, sm_CurrentScale)
64 Next
65 End SyncLock
66 End Sub
67
68End Class
This value is stored so we can set new controls, and then applied to all of the currently attached controls. I have chosen to bind to a slider, but any way of passing in the required values is just fine.
1<igRibbon:XamRibbonWindow x:Class="MainWindowView"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:igRibbon="http://infragistics.com/Ribbon"
5 xmlns:igEditors="http://infragistics.com/Editors"
6 xmlns:igWindows="http://infragistics.com/Windows"
7 xmlns:igDock="http://infragistics.com/DockManager"
8 xmlns:local="clr-namespace:Hinshlabs.WpfHeatItsmDashboard"
9 Title="Heat Itsm Dashboard" MinHeight="600" MinWidth="800" Icon="/Hinshlabs.WpfHeatItsmDashboard;component/HeatItsm.ico">
10 <igRibbon:XamRibbonWindow.Resources>
11 <local:NinjectDataProvider
12 x:Key="ViewModel"
13 ObjectType="{x:Type local:MainWindowViewModel}"
14 />
15 </igRibbon:XamRibbonWindow.Resources>
16 <igRibbon:RibbonWindowContentHost DataContext="{StaticResource ViewModel}">
17 <igRibbon:RibbonWindowContentHost.Ribbon>
18 <igRibbon:XamRibbon local:XamRibbonBehaviour.IsEntryPoint="True" DockPanel.Dock="Top" AutoHideEnabled="True" Theme="Office2k7Blue" >
19 <igRibbon:XamRibbon.ApplicationMenu>
20 <igRibbon:ApplicationMenu RecentItemsHeader="{Binding Resources.RecentItemsHeader}" Image="/Hinshlabs.WpfHeatItsmDashboard;component/Images/heat.gif">
21 <igRibbon:ButtonTool Caption="Update" />
22 <igRibbon:ApplicationMenu.FooterToolbar>
23 <igRibbon:ApplicationMenuFooterToolbar>
24 <igRibbon:ButtonTool Command="{Binding ExitCommand}" Caption="{Binding Resources.ExitButtonCaption}"/>
25 </igRibbon:ApplicationMenuFooterToolbar>
26 </igRibbon:ApplicationMenu.FooterToolbar>
27 </igRibbon:ApplicationMenu>
28 </igRibbon:XamRibbon.ApplicationMenu>
29 <igRibbon:XamRibbon.Tabs>
30 <igRibbon:RibbonTabItem Header="{Binding Resources.Ribbon_HomeTab_Header}">
31 <igRibbon:RibbonGroup Caption="{Binding Resources.Ribbon_HomeTab_ViewsGroup_Caption}">
32 <igRibbon:ToolHorizontalWrapPanel>
33 <igRibbon:ButtonTool Caption="{Binding Resources.Ribbon_HomeTab_ViewsGroup_CallsViewButtonCaption}" Command="{Binding AddCallsViewCommand}" />
34 </igRibbon:ToolHorizontalWrapPanel>
35 </igRibbon:RibbonGroup>
36 <igRibbon:RibbonGroup Caption="{Binding Resources.Ribbon_HomeTab_OptionsGroup_Caption}">
37 <igRibbon:ToolHorizontalWrapPanel>
38 <igRibbon:ButtonGroup>
39 <igRibbon:ToggleButtonTool IsChecked="{Binding FickEnabled, Mode=TwoWay}" Content="{Binding Resources.Ribbon_HomeTab_OptionsGroup_Flick_ToggleButton_Caption}"/>
40 </igRibbon:ButtonGroup>
41 </igRibbon:ToolHorizontalWrapPanel>
42 <igRibbon:ToolHorizontalWrapPanel>
43 <igRibbon:ButtonGroup>
44 <Label Content="Scale" />
45 <Slider Minimum="0.5" Maximum="3" Width="200" local:GlobalScaleTransformBehaviour.ScaleValue="1" LargeChange=".5" SmallChange=".1" Value="{Binding Path=(local:GlobalScaleTransformBehaviour.ScaleValue),RelativeSource={RelativeSource Self}, Mode=TwoWay}">
46 </Slider>
47 </igRibbon:ButtonGroup>
48 </igRibbon:ToolHorizontalWrapPanel>
49 </igRibbon:RibbonGroup>
50 </igRibbon:RibbonTabItem>
51 </igRibbon:XamRibbon.Tabs>
52 </igRibbon:XamRibbon>
53 </igRibbon:RibbonWindowContentHost.Ribbon>
54 <AdornerDecorator>
55 <DockPanel>
56 <local:UpdateView DockPanel.Dock="Top" />
57 <igWindows:XamTabControl TabItemCloseButtonVisibility="Visible" TabStripPlacement="Top" ItemsSource="{Binding CallsViews}" SelectedItem="{Binding SelectedCallsView}" local:TabControlTimedBehaviour.IsTimedCycle="{Binding FickEnabled}" Theme="Office2k7Blue">
58 </igWindows:XamTabControl>
59 </DockPanel>
60 </AdornerDecorator>
61 </igRibbon:RibbonWindowContentHost>
62</igRibbon:XamRibbonWindow>
As you can see I am heavily utilizing the Infragistics controls, but that would not affect this procedure. The result is the ability to smoothly scale your controls based on a global scale setting.
krsu46zvpt
Technorati Tags: .NET WPF CodeProject MVVM
No related videos found.
If you've made it this far, it's worth connecting with our principal consultant and coach, Martin Hinshelwood, for a 30-minute 'ask me anything' call.
We partner with businesses across diverse industries, including finance, insurance, healthcare, pharmaceuticals, technology, engineering, transportation, hospitality, entertainment, legal, government, and military sectors.
NIT A/S