可拖拽面板的WPF实现
这里要实现的功能,就是类似Blend中间的工作面板——可以缩放和拖动其中的内容。
这个功能的实现方式应该有不少。而且在Blend 3当中加入了MouseDragElementBehavior,这个功能的实现似乎就更简单了,但是MouseDragElementBehavior是基于RenderTransform来实现拖动的效果的。结果就是滚动条不能正确地显示出来。
下面给出了一个相对比较简单的解决方案,用一个CustomControl实现了缩放和拖拽功能,同时滚动条也能正常显示。
代码如下:
DesignViewer
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
namespace DesignView
{
/// <summary>
///
/// </summary>
public class DesignViewer : ContentControl
{
#region Private Fields
private Thickness beginMargin;
private Viewbox viewbox;
#endregion
#region Constructors
static DesignViewer()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DesignViewer), new FrameworkPropertyMetadata(typeof(DesignViewer)));
}
#endregion
#region Event Handlers
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
viewbox = Template.FindName("PART_Viewbox", this) as Viewbox;
Thumb thumb = Template.FindName("PART_Thumb", this) as Thumb;
if (viewbox != null)
{
viewbox.PreviewMouseLeftButtonDown += OnThumbPreviewMouseLeftButtonDown;
}
if (thumb != null)
{
thumb.DragDelta += OnDragDelta;
thumb.DragStarted += OnDragStarted;
}
}
private void OnThumbPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
private void OnDragDelta(object sender, DragDeltaEventArgs e)
{
viewbox.Margin = new Thickness()
{
Top = beginMargin.Top + e.VerticalChange * 2,
Left = beginMargin.Left + e.HorizontalChange * 2
};
}
private void OnDragStarted(object sender, DragStartedEventArgs e)
{
beginMargin = viewbox.Margin;
}
#endregion
}
}
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
namespace DesignView
{
/// <summary>
///
/// </summary>
public class DesignViewer : ContentControl
{
#region Private Fields
private Thickness beginMargin;
private Viewbox viewbox;
#endregion
#region Constructors
static DesignViewer()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DesignViewer), new FrameworkPropertyMetadata(typeof(DesignViewer)));
}
#endregion
#region Event Handlers
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
viewbox = Template.FindName("PART_Viewbox", this) as Viewbox;
Thumb thumb = Template.FindName("PART_Thumb", this) as Thumb;
if (viewbox != null)
{
viewbox.PreviewMouseLeftButtonDown += OnThumbPreviewMouseLeftButtonDown;
}
if (thumb != null)
{
thumb.DragDelta += OnDragDelta;
thumb.DragStarted += OnDragStarted;
}
}
private void OnThumbPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
private void OnDragDelta(object sender, DragDeltaEventArgs e)
{
viewbox.Margin = new Thickness()
{
Top = beginMargin.Top + e.VerticalChange * 2,
Left = beginMargin.Left + e.HorizontalChange * 2
};
}
private void OnDragStarted(object sender, DragStartedEventArgs e)
{
beginMargin = viewbox.Margin;
}
#endregion
}
}
其Style如下所示:
Design Viewer Style
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DesignView">
<Style x:Key="DragThumbStyle"
TargetType="{x:Type Thumb}">
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Background="#00000000"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="DesignViewerTemplate"
TargetType="{x:Type local:DesignViewer}">
<DockPanel>
<Slider x:Name="slider"
Value="1" Maximum="25"
DockPanel.Dock="Top"/>
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<Grid>
<Thumb x:Name="PART_Thumb"
Style="{StaticResource DragThumbStyle}"/>
<Viewbox x:Name="PART_Viewbox" Stretch="None"
RenderTransformOrigin="0.5,0.5">
<Viewbox.LayoutTransform>
<ScaleTransform ScaleX="{Binding Value, ElementName=slider}"
ScaleY="{Binding Value, ElementName=slider}"/>
</Viewbox.LayoutTransform>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Viewbox>
</Grid>
</ScrollViewer>
</DockPanel>
</ControlTemplate>
<Style TargetType="{x:Type local:DesignViewer}">
<Setter Property="Template"
Value="{StaticResource DesignViewerTemplate}"/>
</Style>
</ResourceDictionary>
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DesignView">
<Style x:Key="DragThumbStyle"
TargetType="{x:Type Thumb}">
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Background="#00000000"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="DesignViewerTemplate"
TargetType="{x:Type local:DesignViewer}">
<DockPanel>
<Slider x:Name="slider"
Value="1" Maximum="25"
DockPanel.Dock="Top"/>
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<Grid>
<Thumb x:Name="PART_Thumb"
Style="{StaticResource DragThumbStyle}"/>
<Viewbox x:Name="PART_Viewbox" Stretch="None"
RenderTransformOrigin="0.5,0.5">
<Viewbox.LayoutTransform>
<ScaleTransform ScaleX="{Binding Value, ElementName=slider}"
ScaleY="{Binding Value, ElementName=slider}"/>
</Viewbox.LayoutTransform>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Viewbox>
</Grid>
</ScrollViewer>
</DockPanel>
</ControlTemplate>
<Style TargetType="{x:Type local:DesignViewer}">
<Setter Property="Template"
Value="{StaticResource DesignViewerTemplate}"/>
</Style>
</ResourceDictionary>
其中,使用了Viewbox和Slider来控制缩放,使用了Thumb控件控制拖拽功能,当然还使用了一个ScrollViewer来显示滚动条。
完整的程序可以在这里下载。