65.9K
CodeProject 正在变化。 阅读更多。
Home

将 UIElement/FrameworkElement 转换为图像

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (2投票s)

2011 年 12 月 27 日

CPOL

2分钟阅读

viewsIcon

41201

downloadIcon

749

将 ScrollViewer 内容转换为 Image


 

引言

FramewrokElement 类为 Windows Presentation Foundation (WPF) 元素提供框架级别的属性、事件和方法。

FrameworkElement (FE) 派生自 UIElement

UIElement  是基于 Windows Presentation Foundation (WPF) 元素和基本呈现特征构建的 WPF 核心级实现的基类。

背景

在本文中,我将解释如何将 UIElement 转换为 ImageSource。

RenderTargetBitmap System.Windows.Media 的属性,用于将视觉对象转换为位图。

DrawingVisual 用于渲染矢量图形。

使用代码

我创建了 TreeView,并从集合中绑定父级和子级树项。

步骤 1:创建模型。

Area.cs

  public class Area
    {
        public string AreaName { get; set; }
        public string Description { get; set; }        
    } 

此类用于子节点。

Location.cs

  public class Location
    {
        public string LocationName { get; set; }
        public List<Area> AreaList { get; set; }      
    } 

此类包含父树节点和每个父节点的子节点集合的属性。

步骤 2:创建 ViewModel 以绑定集合。

MainViewmodel.cs

  public class MainViewmodel
    {
        private ObservableCollection<Location> _locations;
        public ObservableCollection<Location> Locations
        {
            get { return _locations; }
            set { _locations = value; }
        }
        public MainViewmodel()
        {
            Locations = new ObservableCollection<Location>();
            BindLocationList();
        }
        List<Area> GetAreaList()
        {
            List<Area> returnList = new List<Area>();
            returnList.Add(new Area() { AreaName = "Kankaria",  Description = "The state has witnessed all-round progress in every field..." });
            returnList.Add(new Area() { AreaName = "Swapnasrusthi", Description = "The state has witnessed all-round progress in every field..." });
            returnList.Add(new Area() { AreaName = "Scien city", Description = "The state has witnessed all-round progress in every field..."});

            returnList.Add(new Area() { AreaName = "Lal quila", Description = "The state has witnessed all-round progress in every field..." });
            returnList.Add(new Area() { AreaName = "lake view", Description = "The state has witnessed all-round progress in every field..."});

            returnList.Add(new Area() { AreaName = "Shilalekh", Description = "The state has witnessed all-round progress in every field..."});
            returnList.Add(new Area() { AreaName = "Girnar",  Description = "The state has witnessed all-round progress in every field..."});
            returnList.Add(new Area() { AreaName = "Zoo", Description = "The state has witnessed all-round progress in every field..."});

            returnList.Add(new Area() { AreaName = "chandani chowk", Description = "The state has witnessed all-round progress in every field..."});
            returnList.Add(new Area() { AreaName = "Akshradham", Description = "The state has witnessed all-round progress in every field..."});
            returnList.Add(new Area() { AreaName = "Qutub minar", Description = "The state has witnessed all-round progress in every field..."});

            return returnList;
        }
        void BindLocationList()
        {
            List<Area> areaList = GetAreaList();
            List<Location> locationList = new List<Location>();
            locationList.Add(new Location() { LocationName = "Ahmedabad", AreaList = areaList.Take(3).ToList() });
            locationList.Add(new Location() { LocationName = "Jamnagar", AreaList = areaList.Skip(3).Take(2).ToList() });
            locationList.Add(new Location() { LocationName = "Junagadh", AreaList = areaList.Skip(5).Take(3).ToList() });
            locationList.Add(new Location() { LocationName = "Delhi", AreaList = areaList.Skip(8).Take(3).ToList() });
            Locations = new ObservableCollection<Location>(locationList);
        }
    } 

在上面的代码中,我创建了 Locations 的 ObservableCollection,它提供有关添加/编辑项目的通知。

在位置内绑定位置和区域。

步骤 3:为 TreeView 创建模板。

MainWindow.xaml

 <DataTemplate x:Key="AreaDataTemplate">
            <StackPanel Orientation="Vertical">
                <TextBlock Text="{Binding AreaName}"
                           VerticalAlignment="Center"
                           Margin="5"
                           Style="{StaticResource TextBlockStyle2}" />
                <TextBlock Text="{Binding Description}"
                           Width="300"
                           Style="{StaticResource TextBlockStyle2}" />
            </StackPanel>
        </DataTemplate> 

DataTemplate 为您提供了极大的灵活性来定义数据的呈现方式。

DataTemplate  为您提供了一个非常灵活且强大的解决方案,可以替换数据项的视觉外观在 ListBox、ComboBox 或 ListView 等控件中。

绑定子树项并在 treeview 中呈现子节点的布局。 

 <HierarchicalDataTemplate x:Key="LocationTemplate"
                                  ItemsSource="{Binding AreaList}"
                                  ItemTemplate="{StaticResource AreaDataTemplate}">
            <TextBlock Text="{Binding LocationName}"
                       Margin="5 5 10 10"
                       Style="{StaticResource TextBlockStyle}" />
        </HierarchicalDataTemplate>

HierarchicalDataTemplate 表示支持 HeaderedItemControl 的 DataTemplat ,例如 TreeViewItems. 

将 ItmesSource 绑定到 AreaList(用于子 TreeViewItems)并将 ItemTemplate 绑定到子 DataTemplate 资源键。

步骤 4:将 TreeView 放置到 Window 中。

MainWindow.xaml

 <Grid Grid.Row="1"
                      MaxHeight="250">
                    <TreeView ScrollViewer.CanContentScroll="True"
                              BorderThickness="0"
                              Background="#FFF"
                              ItemsSource="{Binding Locations}"
                              ItemTemplate="{DynamicResource LocationTemplate}"
                              x:Name="LocationTreeView" />
                </Grid> 

我将 TreeView 放置在 Grid 中,并将其 CanContentScroll 属性设置为 true,当树节点展开且高度超过 250 时,这将添加滚动条。

使用 Locations 绑定 ItemsSource,并将 ItemTemplate 设置为 HierarchicalDataTemplate。

步骤 5:放置 Button,它执行将 UIElement 转换为 ImageSource 的代码。

Grid Grid.Row="1">
                <Button Content="Generate Image"
                        x:Name="convert"
                        Width="100"
                        Grid.Row="1"
                        Height="25"
                        Click="convert_Click" />
            </Grid>
步骤 6:将 Image 放置到窗口中,以从 UIElement 设置 Source。
<Grid Grid.Row="2"
                  MaxWidth="400"
                  MinHeight="400">
                <Image x:Name="displayImage"
                       Grid.Row="2"
                       Stretch="Fill"
                       Margin="0 0 0 30" />
            </Grid>
步骤 7:创建方法以从父 UIElement 中查找 UIElement
   private ScrollViewer GetTemplateChildByName(DependencyObject parent)
        {
            int childnum = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < childnum; i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i);
                if (child is ScrollViewer)
                {
                    return child as ScrollViewer;
                }
                else
                {
                    var s = GetTemplateChildByName(child);
                    if (s != null)
                        return s;
                }
            }
            return null;
        } 

此方法在父 UIElement 中查找 UIElement。 它将使用 VisualTreeHelper 的 GetChild 方法查找子元素。

VisualTreeHelper 提供了执行涉及视觉树中节点的常见任务的实用程序方法。

VisualTreeHelper.GetChild 方法从指定父级中的指定集合索引返回子视觉对象。

我编写了这个方法来查找 TreeView 中的 ScrollViewer。

步骤 8:编写代码以从 UIElement 转换 ImageSource。

private void convert_Click(object sender, RoutedEventArgs e)
        {
            ScrollViewer scroll = GetTemplateChildByName(LocationTreeView);
            if (scroll != null)
            {
                ItemsPresenter item = scroll.Content as ItemsPresenter;
                double width = item.ActualWidth;
                double height = item.ActualHeight;
                RenderTargetBitmap bmpCopied = new RenderTargetBitmap((int)Math.Round(width), (int)Math.Round(height), 100, 100, PixelFormats.Default);
                DrawingVisual drawingVisual = new DrawingVisual();
                using (DrawingContext drawingContext = drawingVisual.RenderOpen())
                {
                    VisualBrush visualBrush = new VisualBrush(item);
                    drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(), new Size(width, height)));
                }
                bmpCopied.Render(drawingVisual);
                displayImage.Source = bmpCopied;
            }
        }

在 Button 点击事件处理程序中,我编写了将 TreeView 内容转换为 ImageSource 的代码。

首先在 TreeView 中找到 ScrollViewer。

之后从 ScrollViewer 内容中获取 ItemPresenter,因为我们需要将完整的可扩展 TreeView 转换为 ImageSource。

如果您获得 TreeView/ScrollViewer 的 ActualHeight ,它将仅提供可见区域高度,因此它只会将可见区域转换为图像而不是滚动区域。

为了转换隐藏的滚动区域以及可见区域,您必须将 ScrollViewer 内容作为 ItemPresenter 获取,并使用 ItemPresenter 元素及其 ActualWidth/ActualHeight 属性绘制图像。


关注点

当您使用 ScrollViewer 时,

始终在其内容区域中使用宽度和高度计算。

它将给出 ScrollViewer 内内容的 ActualHeight/ActualWidth。


© . All rights reserved.