WPF: FishEyePanel/FanPanel - 自定义Panel

简介: 原文:WPF: FishEyePanel/FanPanel - 自定义Panel 原文来自CodeProject,主要介绍如何创建自定义的Panel,如同Grid和StackPanel。
原文: WPF: FishEyePanel/FanPanel - 自定义Panel

原文来自CodeProject,主要介绍如何创建自定义的Panel,如同Grid和StackPanel。

1) Introduction

文中介绍了两种Panel:FishPanel(鱼眼面板,点击时当前面板变大,其它面板变小,但整体宽度不变),FanPanel(帆面板,不知如何翻译比较贴切,就这样吧;子面板位置,大小都可以改变,同样整体宽度不变)。

2)Using the Code

最低版本VS2005,.Net 3.0;

3)Writing a custom panel

创建自定义的窗体,需要从System.Windows.Controls.Panel派生新类,然后重写:MeasureOverride和LayoutOverride。在计算阶段,调用者可以确认它需要多大的空间;也帮助我们确认子控件的大小;接下来就是把最终的大小参数传递到ArrangeOverride方法;每次我们队Layout有改变时,上面的两步操作会重复发生的。

protected override Size MeasureOverride(Size availableSize)
{
    Size idealSize = new Size(0, 0);

    // Allow children as much room as they want - then scale them
    Size size = new Size(Double.PositiveInfinity, Double.PositiveInfinity);
    foreach (UIElement child in Children)
    {
        child.Measure(size);
        idealSize.Width += child.DesiredSize.Width;
        idealSize.Height = Math.Max(idealSize.Height, 
                           child.DesiredSize.Height);
    }

    // EID calls us with infinity, but framework
    // doesn't like us to return infinity
    if (double.IsInfinity(availableSize.Height) || 
        double.IsInfinity(availableSize.Width))
        return idealSize;
    else
        return availableSize;
}

在MeasureOverride中,让子控件来决定我们所需的空间大小,这是通过属性Child.DesiredSize来获得的;接下来就是调整比例大小,使其适应整个窗体。

protected override Size ArrangeOverride(Size finalSize)
{
    if (this.Children == null || this.Children.Count == 0)
        return finalSize;

    ourSize = finalSize;
    totalWidth = 0;

    foreach (UIElement child in this.Children)
    {
        // If this is the first time
        // we've seen this child, add our transforms
        if (child.RenderTransform as TransformGroup == null)
        {
            child.RenderTransformOrigin = new Point(0, 0.5);
            TransformGroup group = new TransformGroup();
            child.RenderTransform = group;
            group.Children.Add(new ScaleTransform());
            group.Children.Add(new TranslateTransform());
            //group.Children.Add(new RotateTransform());
        }

        child.Arrange(new Rect(0, 0, child.DesiredSize.Width, 
                      child.DesiredSize.Height));

        totalWidth += child.DesiredSize.Width;
    }

    AnimateAll();

    return finalSize;
}

在ArrangeOverride中,添加了比例计算,对每一个子控件都做变换,再统计总宽度;可以实现不同子控件变为相同宽度,或选择同样比例变成不同宽度,这是通过属性ScaleToFit来实现(代码中没看到?)。现在,我们只是把控件放在(0,0)处,接下来就是使用RenderTransoforms来移动控件。

鱼眼面板:设置3个子控件比其它的都大,所选哪3个控件是取决于当前鼠标的位置,其它的控件会填充余下的空间;

范面板:对子控件的旋转,缩放,平移来使控件以这三种方式排列:堆叠(stacked up),爆炸(exploded),包裹(wrap)

无论是鱼眼面板还是范面板,核心的处理过程都在AnimateAll(),可以查看它们的源代码。

4)Points of interest

无法在设计时直接以ItemControl方式显示,我们不能只指定一个名字就行,这是由于这两个控件只是一个模板,并不是真正的控件。作者想到了一个方法是:与Loaded事件相关联,然后把Sender转化为相关的面板模式。

为了演示界面效果,由于使用XPath和Binding不是很方便,作者使用了XmlDataProvider来加载所有图像。可在项目中先单独加载图像到一个Images文件夹,在TestData.xaml中我们看到:

<XmlDataProvider x:Key="Things" XPath="Things/Thing">
 <x:XData>
  <Things xmlns="">
    <Thing Image="Aquarium.jpg"/>
    <Thing Image="Ascent.jpg"/>
    <Thing Image="Autumn.jpg"/>
    <Thing Image="Crystal.jpg"/>
    <Thing Image="DaVinci.jpg"/>
    <Thing Image="Follow.jpg"/>
    <Thing Image="Friend.jpg"/>
    <Thing Image="Home.jpg"/>
    <Thing Image="Moon flower.jpg"/>
  </Things>
 </x:XData>
</XmlDataProvider>

在App.xaml中引用这些资源,使它们在整个项目中都可见。

<ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>

        <ResourceDictionary Source="Resources/TestData.xaml" />

      </ResourceDictionary.MergedDictionaries>
      <local:ImagePathConverter x:Key="ImagePathConverter" />
</ResourceDictionary>

5)FishEye Panel Demo

5.1)设置界面背景色:

<Window.Background>
    <ImageBrush ImageSource="Images/Azul.jpg" />
</Window.Background>

5.2)设置7行:

<Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="*"/>
      <RowDefinition Height="2*"/>
      <RowDefinition Height="*"/>
      <RowDefinition Height="2*"/>
      <RowDefinition Height="*"/>
      <RowDefinition Height="2*"/>
      <RowDefinition Height="*"/> 
    </Grid.RowDefinitions>
 </Grid>

5.3)设置第二行:

<Border CornerRadius="10" Background="#99ffffff" Grid.Row="1">
      <ItemsControl DataContext="{Binding Source={StaticResource Things}}" ItemsSource="{Binding}" Margin="0">
        <ItemsControl.ItemsPanel>
          <ItemsPanelTemplate>
            <local:FishEyePanel Loaded="FishEye_Loaded" Magnification="3" AnimationMilliseconds="150" ScaleToFit="true"/>
          </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemContainerStyle>
          <Style TargetType="{x:Type ContentPresenter}">
            <Setter Property="ContentTemplate">
              <Setter.Value>
                <DataTemplate> 
                  <!-- This could obviously be any XAML. In our POC we dropped in entire UI pages and used it like a Vista taskbar -->
                  <Image Source="{Binding Converter={StaticResource ImagePathConverter}, XPath=@Image}" Width="{Binding XPath=@Width}" Margin="5"/>
                </DataTemplate>
              </Setter.Value>
            </Setter>
          </Style>
        </ItemsControl.ItemContainerStyle>

      </ItemsControl>
 </Border> 

上面设置了FishEyePanel的Loaded事件,及Image Source。

5.4)在主窗体cs文件中添加Loaded事件处理过程:

void FishEye_Loaded(object sender, RoutedEventArgs e)
{
      fish = (FishEyePanel)sender;
}

5.5)演示界面(除去了后面两行的图像显示);点击其中的一张照片,左右的照片也一起变大,其余的照片不变;


实际上还有很多疑问,如不知如何改变图片的高度等。

附上FishEyePanel的源代码

5.6)FanPanel演示:默认状态


鼠标放在其上:


鼠标点击:


改变Detail Level值后的效果:


附上FanPanel的源代码。


目录
相关文章
|
C# 虚拟化 索引
【WPF】UI虚拟化之------自定义VirtualizingWrapPanel
原文:【WPF】UI虚拟化之------自定义VirtualizingWrapPanel 前言 前几天QA报了一个关于OOM的bug,在排查的过程中发现,ListBox控件中被塞入了过多的Item,而ListBox又定义了两种样式的ItemsPanelTemplate。
2023 0
|
C# 数据安全/隐私保护
【WPF】右下角弹出自定义通知样式(Notification)——简单教程
原文:【WPF】右下角弹出自定义通知样式(Notification)——简单教程 1.先看效果 2.实现 1.主界面是MainWindow 上面就只摆放一个Button即可。
2814 0
|
前端开发 C# 图形学
【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示
Wpf开发过程中,最经常使用的功能之一,就是用户控件(UserControl)了。用户控件可以用于开发用户自己的控件进行使用,甚至可以用于打造一套属于自己的UI框架。依赖属性(DependencyProperty)是为用户控件提供可支持双向绑定的必备技巧之一,同样用处也非常广泛。
783 0
【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示
|
C#
WPF 4 DataGrid 控件(自定义样式篇)
原文:WPF 4 DataGrid 控件(自定义样式篇)      在《WPF 4 DataGrid 控件(基本功能篇)》中我们已经学习了DataGrid 的基本功能及使用方法。本篇将继续介绍自定义DataGrid 样式的相关内容,其中将涉及到ColumnHeader、RowHeader、Row、Cell 的各种样式设置。
2467 0
|
C#
WPF 控件自定义背景
<!--控件要设置尺寸的话,设置的尺寸必须比下面的图形的尺寸要小,不然显示不开--> <Label Content="直角测试" Width="90" Height="90" HorizontalContentAlignment="Center" Vert...
984 0
|
C#
WPF开发-Label自定义背景-Decorator
首先在App.xaml文件当中添加样式和模板
1957 0
|
C#
wpf 开发 -TextBox背景自定义-Decorator
首先在app.xaml文件的下面添加以下样式
1630 0
|
C# 开发工具 git
WPF实现选项卡效果(3)——自定义动态添加的AvalonDock选项卡内容
原文:WPF实现选项卡效果(3)——自定义动态添加的AvalonDock选项卡内容 简介   在前面一篇文章里面,我们实现了AvalonDock选项卡的动态添加,但是对于选项卡里面的内容,我们并没有实现任何有用的功能。
1292 0
|
C#
WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探
原文:WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探         最近因为项目需要,开始学习如何使用WPF开发桌面程序。
1491 0
|
C#
如何自定义WPF项目的Main函数
原文:如何自定义WPF项目的Main函数   与Winform项目不同,WPF项目的Main函数在项目生成的时候,系统自动在后台为我们生成。
803 0