你如何让Canvas.SetTop处理ItemsCollection项目?

时间:2013-06-11 21:54:25

标签: c# wpf canvas observablecollection itemscontrol

以下是完整的程序(XAML和后面的代码)。启动时,您会看到: enter image description here

单击[显示/隐藏]时,您会看到: enter image description here

取消选中主页和文档并单击[应用]时,您会看到: enter image description here

如您所见,“主页”和“文档”文件夹消失,但其他文件夹不会向上移动。查看两个列表框,您会看到每行三个项目,文件夹标签,Canvas.SetTop的值和True:Visibility.Visible或False:Visibility.Collapsed。原始放置列表框是原始值。每次单击[应用]时,“新建放置列表”框都会显示新值。应用Visibility值并且结果可见,文件夹是否存在或不存在。但是,应用Canvas.SetTop不起作用。您可以看到Canvas.SetTop的值已更改。而且,如果您查看代码,您会看到它应用于与应用程序可用性相同的UIElement:

                    var f = Me[i];
                    Canvas.SetTop(iec, f.Top);          // Why does this not work and
                    iec.Visibility = f.FolderVisible;   // this does work?

我需要可见的文件夹向上移动以代替折叠的文件夹。 Canvas.SetTop不起作用。如何让文件夹移动?

以下是解决方案资源管理器窗格,以便您了解所需内容: enter image description here

这是XAML:

<Window x:Class="FolderTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:system="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:FolderTest"
        Title="Folder Test"
        Width="450"
        Height="410">
    <Grid Margin="10">
        <StackPanel Orientation="Horizontal">
            <StackPanel Orientation="Vertical">
                <!-- Folder Show/Hide Button -->
                <Button Name="FolderOptions" Content="Show/Hide" FontSize="8" FontWeight="Bold" Width="50" Height="20" Margin="116, 0, 0, 0" Click="Event_ShowHide_ButtonClick" />
                <!-- Folders -->
                <Grid>
                    <Canvas Name="xFolders"
                            Width="170"
                            Height="309"
                            VerticalAlignment="Top"
                            HorizontalAlignment="Left"
                            Margin="0,10,0,0">
                        <Canvas.Resources>
                            <local:Folders x:Key="myFolders" />
                        </Canvas.Resources>
                        <ItemsControl ItemsSource="{Binding Source={StaticResource myFolders}}">
                            <ItemsControl.Template>
                                <ControlTemplate>
                                    <ItemsPresenter />
                                </ControlTemplate>
                            </ItemsControl.Template>
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <Canvas />
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <DataTemplate.Resources>
                                    </DataTemplate.Resources>
                                    <Canvas Name="FolderCanvas"
                                            Tag="{Binding Path=Number}"
                                            Visibility="{Binding Path=FolderVisible}">
                                        <Path Data="{Binding Path=FolderPath}"
                                              Stroke="{Binding Path=Brush}"
                                              Fill="{Binding Path=Brush}"/>
                                        <StackPanel Orientation="Horizontal"
                                                    Canvas.Left="5"
                                                    Canvas.Top="2">
                                            <TextBlock Text="{Binding Path=Label}"
                                                       FontSize="12"
                                                       Margin="20, 0, 0, 0" />
                                        </StackPanel>
                                    </Canvas>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                            <ItemsControl.ItemContainerStyle>
                                <Style>
                                    <Setter Property="Canvas.Top"
                                            Value="{Binding Top}" />
                                </Style>
                            </ItemsControl.ItemContainerStyle>
                        </ItemsControl>
                    </Canvas>
                </Grid>
            </StackPanel>
            <StackPanel Orientation="Vertical" Margin="10, 0, 0, 0">
                <TextBlock Text="Original Placemet:" />
                <ListBox Name="OriginalPlacement" />
                <Button Name="Refresh" Content="New Placemet:" Margin="0, 10, 0, 0" Click="Event_OriginalPlacement_ButtonClick" />
                <ListBox Name="NewPlacement" />
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>

这是C#Code Behind:

using System;
using System.Collections.Generic;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows;
using System.Collections.ObjectModel;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

namespace FolderTest
{
    public struct GD
    {
        public static MainWindow MainWindow = null;
        public static Button Refresh = null;
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            GD.MainWindow = this;
            InitializeComponent();
            Loaded += new RoutedEventHandler(MainWindow_Loaded);
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            GD.Refresh = Refresh;
            Folders.Placement(ref OriginalPlacement);
        }

        private void Event_ShowHide_ButtonClick(object sender, RoutedEventArgs e)
        {
            var pu = Folders.FolderShowPopUp();
            pu.PlacementTarget = FolderOptions;
            pu.IsOpen = true;
        }

        private void Event_OriginalPlacement_ButtonClick(object sender, RoutedEventArgs e)
        {
            Folders.Placement(ref NewPlacement);
        }
    }

    public class Folder
    {// Specification for each folder tab seen on the left.
        public int Number { get; set; }                         // Folder sequence number top to bottom starging with 1.
        public string Label { get; set; }                       // The label that appears on the folder tab itself.
        public double Top { get; set; }                         // Position of the upper left corner of this folder.
        public SolidColorBrush Brush { get; set; }              // Solid Color Brush.
        public string FolderPath { get; set; }                  // Contains the geometric path to draw this folder and its tab.
        public Visibility FolderVisible { get; set; }           // This folder's Show/Hide flag.

        public Folder(int Number, string Label, double Top, SolidColorBrush Brush, string FolderPath, Visibility FolderVisible)
        {
            this.Number = Number;
            this.Label = Label;
            this.Top = Top;
            this.Brush = Brush;
            this.FolderPath = FolderPath;
            this.FolderVisible = FolderVisible;
        }
    }

    public class Folders : ObservableCollection<Folder>
    {

        public static ObservableCollection<Folder> Me = null;

        private static string[] Labels = new string[]
        {
            "Personal",
            "Health",
            "Finances",
            "Home",
            "Employment",
            "Insurance",
            "Documents",
            "Contacts",
            "Journal"
        };

        private static Dictionary<string, Tuple<bool, bool>> LabelData = new Dictionary<string, Tuple<bool, bool>>()
        {//  Label                            Show  Hidable
            {Labels[0], new Tuple<bool, bool>(true, false)},
            {Labels[1], new Tuple<bool, bool>(true, true)},
            {Labels[2], new Tuple<bool, bool>(true, true)},
            {Labels[3], new Tuple<bool, bool>(true, true)},
            {Labels[4], new Tuple<bool, bool>(true, true)},
            {Labels[5], new Tuple<bool, bool>(true, true)},
            {Labels[6], new Tuple<bool, bool>(true, true)},
            {Labels[7], new Tuple<bool, bool>(true, false)},
            {Labels[8], new Tuple<bool, bool>(true, true)}
        };

        private static string[] FolderColors = new string[]
        {
            "FF36579E",
            "FFDF2024",
            "FF16A146",
            "FF00B2D4",
            "FFF47B20",
            "FF9F1F63",
            "FF13A89E",
            "FFB7B7E7",
            "FF50CAF5",
            "FFAA9E74",
            "FF86787D",
            "FF36D146",
        };

        private static byte[] ARGBColor = new byte[4];         // Byte array for the folder top color.
        private static void ColorString2ARGB(ref byte[] bytes, string Hex)
        {// Converts 8 char hex string to 4 byte array.
            for (int i = 0; i < 8; i += 2)
                bytes[i / 2] = Convert.ToByte(Hex.Substring(i, 2), 16);
        }

        private static int colorIndex = -1; // Initial value of the colorIndex.
        private static string NextColor()
        {// Returns a 8 char string containing the next top FolderColor.  If at end, cycle to beginning.
            colorIndex++;
            if (colorIndex >= FolderColors.Length) colorIndex = 0;
            return FolderColors[colorIndex];
        }

        private class FolderShow
        {
            public string Label { get; set; }
            public bool Show { get; set; }
            public bool Hidable { get; set; }
            public FolderShow(string label, bool show, bool hidable)
            {
                Label = label;
                Show = show;
                Hidable = hidable;
            }
        }
        private static List<FolderShow> FolderShowList = null;

        public static Popup FolderShowPopUp()
        {
            var pu = new Popup()
            {
                Placement = PlacementMode.Right,
                AllowsTransparency = true,
                StaysOpen = false
            };
            var b = new Border()
            {
                BorderThickness = new Thickness(2),
                BorderBrush = new SolidColorBrush() { Color = Colors.Black },
                CornerRadius = new CornerRadius(5),
                Background = new SolidColorBrush() { Color = Colors.White }
            };
            var sp = new StackPanel()
            {
                Orientation = Orientation.Vertical,
                Margin = new Thickness(10)
            };
            var tb = new TextBlock()
            {
                Text = "Checked Folders will be Displayed: ",
                FontSize = 16,
                FontWeight = FontWeights.Bold,
            };

            sp.Children.Add(tb);

            foreach (var fs in FolderShowList)
            {
                var cb = new CheckBox()
                {
                    Content = fs.Label,
                    IsChecked = fs.Show,
                    IsEnabled = fs.Hidable,
                    FontSize = 14,
                    FontWeight = FontWeights.Bold,
                    Margin = new Thickness(0, 5, 0, 0)
                };
                cb.Click += new RoutedEventHandler(Event_CheckBoxFolderList_Click);
                sp.Children.Add(cb);
            }

            var bp = new StackPanel()
            {
                Orientation = Orientation.Horizontal,
                Margin = new Thickness(0, 5, 0, 0)
            };
            var ba = new Button() { Content = "Apply", Width = 50, Height = 25, BorderBrush = new SolidColorBrush(Colors.Transparent), Tag = pu };
            ba.Click += new RoutedEventHandler(Event_ApplyFolderList_Click);
            bp.Children.Add(ba);
            var bc = new Button() { Content = "Cancel", Width = 50, Height = 25, BorderBrush = new SolidColorBrush(Colors.Transparent), Tag = pu, Margin = new Thickness(7, 0, 0, 0) };
            bc.Click += new RoutedEventHandler(Event_CancelFolderList_Click);
            bp.Children.Add(bc);
            sp.Children.Add(bp);

            var tbm = new TextBlock()
            {
                Text = "Disabled folders cannot be hidden.",
                Margin = new Thickness(0, 5, 0, 0),
                FontSize = 12,
                Foreground = new SolidColorBrush()  { Color = Colors.Red }
            };
            sp.Children.Add(tbm);

            b.Child = sp;
            pu.Child = b;

            return pu;
        }

        private static void Event_CheckBoxFolderList_Click(object sender, RoutedEventArgs e)
        {
            var cb = (CheckBox)e.Source;
            foreach (var fs in FolderShowList)
            {
                if (fs.Label == cb.Content as string)
                {
                    fs.Show = (bool)cb.IsChecked;
                    break;
                }
            }
        }

        private static void Event_CancelFolderList_Click(object sender, RoutedEventArgs e)
        {
            ((Popup)((Button)e.Source).Tag).IsOpen = false;
        }

        private static void Event_ApplyFolderList_Click(object sender, RoutedEventArgs e)
        {
            foreach (var fs in FolderShowList)
            {
                var sh = LabelData[fs.Label];
                LabelData[fs.Label] = new Tuple<bool, bool>(fs.Show, sh.Item2);
            }
            ((Popup)((Button)e.Source).Tag).IsOpen = false;

            int p = 0;
            foreach (var f in Me)
            {
                var fs = LabelData[f.Label].Item1 == true;
                f.Top = p * folderPositionFactor;
                f.FolderVisible = fs ? Visibility.Visible : Visibility.Collapsed;
                if (fs) p += 1;
            }
            foreach (ItemsControl ic in GD.MainWindow.xFolders.Children)
            {
                for (int i = 0; i < ic.Items.Count; i++)
                {
                    var ie = (UIElement)ic.ItemContainerGenerator.ContainerFromIndex(i);
                    var iec = Controls.FindChildByType<Canvas>(ie, "FolderCanvas");
                    if (iec != null)
                    {
                        var f = Me[i];
                        Canvas.SetTop(iec, f.Top);          // Why does this not work and
                        iec.Visibility = f.FolderVisible;   // this does work?
                    }
                }
                break;
            }
            GD.Refresh.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
        }

        public static void Placement(ref ListBox lb)
        {
            lb.Items.Clear();
            foreach (ItemsControl ic in GD.MainWindow.xFolders.Children)
            {
                for (int i = 0; i < ic.Items.Count; i++)
                {
                    var ie = (UIElement)ic.ItemContainerGenerator.ContainerFromIndex(i);
                    var iec = Controls.FindChildByType<Canvas>(ie, "FolderCanvas");
                    if (iec != null)
                    {
                        var f = Me[i];
                        lb.Items.Add(f.Label + ": " + f.Top.ToString() + ", " + (f.FolderVisible == Visibility.Visible ? "True" : "False"));
                    }
                }
                break;
            }
        }


        public Folders()
        {// The constructor, initializes itself by creating a folder for each label in Labels
            FolderShowList = new List<FolderShow>();
            for (int i = 0; i < Labels.Length; i++)
            {
                string n = Labels[i];
                bool h = LabelData[Labels[i]].Item2;
                bool s = h == true ? LabelData[Labels[1]].Item1 == true : true;
                FolderShowList.Add(new FolderShow(n, s, h));
            }
            SetFolders();
            Me = this;
        }

        const double folderPositionFactor = 31; // 21.80;
        public void SetFolders()
        {
            SolidColorBrush[] scb = new SolidColorBrush[Labels.Length];           // Hold the linear solid color brush to assign to the folder.
            Color[] pointerColor = new Color[Labels.Length];                      // Hold the color to assign to the folder's solid color brush.

            for (int i = 0; i < Labels.Length; i++)
            {// Create a solid color brush for each folder.
                ColorString2ARGB(ref ARGBColor, NextColor());                                               // Color into byte array.
                Color TmpColor = Color.FromArgb(ARGBColor[0], ARGBColor[1], ARGBColor[2], ARGBColor[3]);    // Create top color.
                pointerColor[i] = TmpColor;
                SolidColorBrush TmpSCB = new SolidColorBrush() { Color = TmpColor };
                scb[i] = TmpSCB; // Assign the solid color brush.
            }

            // All is ready to create the individual folders.
            const string folderHeight = "56"; // "44";
            Brush FontColor = Brushes.Black;                                          // Initial font color for labels.
            string fp = "M0,7 A7,7 90 0 1 7,0 L100,0 105,18 150,18 150,FH 0,FH Z".Replace("FH", folderHeight);  // Initial geometric path for folder design.
            int afp = 0; // Actual Folder Position.
            for (int i = 0; i < Labels.Length; i++)
            {// Create the individual folders.
                bool fs = FolderShowList[i].Show;
                Add(new Folder(
                                i + 1,                                          // Folder sequence count.
                                Labels[i],                                      // Folder label.
                                afp * folderPositionFactor,                     // Position of top of folder.
                                scb[i % scb.Length],                            // Solid color brush.
                                fp,                                             // Geometric path for folder design.
                                fs ? Visibility.Visible : Visibility.Collapsed  // User Hidden.
                              )
                        );
                if (fs) afp += 1;
                if (i == 0)
                {// First folder created, now set values for remaining folders.
                    FontColor = Brushes.White;
                    fp = "M0,25 A7,7 90 0 1 7,18 L13,18 18,0 100,0 105,18 150,18 150,FH 0,FH Z".Replace("FH", folderHeight);
                }
            }
        }
    }

    public static class Controls
    {

        public static T FindChildByType<T>(DependencyObject parent, string childName) where T : DependencyObject
        {
            if (parent == null) return null; // No parent, get out of here.
            T foundChild = null;
            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i);
                // If the child is not of the request child type child
                T childType = child as T;
                if (childType == null)
                {
                    // recursively drill down the tree
                    foundChild = FindChildByType<T>(child, childName);

                    // If the child is found, break so we do not overwrite the found child. 
                    if (foundChild != null) break;
                }
                else if (!string.IsNullOrEmpty(childName))
                {
                    var frameworkElement = child as FrameworkElement;
                    // If the child's name is set for search
                    if (frameworkElement != null && frameworkElement.Name == childName)
                    {
                        // if the child's name is of the request name
                        foundChild = (T)child;
                        break;
                    }
                }
                else
                {
                    // child element found.
                    foundChild = (T)child;
                    break;
                }
            }
            return foundChild;
        }
    }
}

感谢您提供的任何帮助。

1 个答案:

答案 0 :(得分:0)

我终于找到了答案,这很简单。

这是要更改的代码(仅限中心线):

                    var f = Me[i];
                    Canvas.SetTop(iec, f.Top);          // Why does this not work
                    iec.Visibility = f.FolderVisible;   // and this does work?

这是新代码(只更改了中心线,实际上只删除了一个字符):

                    var f = Me[i];
                    Canvas.SetTop(ie, f.Top);
                    iec.Visibility = f.FolderVisible;

也就是说,将Canvas.SetTop(iec, f.Top);更改为Canvas.SetTop(ie, f.Top);,即只将iec更改为ie,一切正常。