小闵的院子

技术之家

导航

Silverlight 之TreeView右键菜单开发

Silverlight 4 toolkit提供了ContextMenu类实现右键菜单,不过由于silverlight技术还处于不完全成熟阶段,许多地方还没有做完善,比如触发右键菜单时,TreeViewItem不被选中。网上找了很多,关于这方面的比较少,最后借鉴WPF技术来实现了该功能。

思路:

(1)添加TreeView右键事件

  MouseRightButtonDown="TreeView_MouseRightButtonDown"

  MouseRightButtonUp="TreeView_MouseRightButtonUp"

(2)在MouseRightButtonDown事件中首先关闭右键菜单(ContextMenu属性IsOpen=false),

  然后通过属性绑定来改变TreeViewItem的选中属性IsSelected为true。

(3)在MouseRightButtonUp中生成自己定制的右键菜单,同进使ContextMenu属性IsOpen=true。

 

例子代码如下:

xaml部分:

   <sdk:TreeView Grid.Row="1" Grid.Column="0" ItemsSource="{Binding TreeRoot.Children}"  

         MouseRightButtonDown="TreeView_MouseRightButtonDown">
            <sdk:TreeView.ItemContainerStyle>
                <Style TargetType="sdk:TreeViewItem">
                    <!-- WPF syntax:
                        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>-->
                    <Setter Property="common:SetterValueBindingHelper.PropertyBinding">
                        <Setter.Value>
                            <common:SetterValueBindingHelper
                                Property="IsSelected"
                                Binding="{Binding IsSelected, Mode=TwoWay}"/>
                        </Setter.Value>
                    </Setter>
                </Style>
            </sdk:TreeView.ItemContainerStyle>
            <sdk:TreeView.ItemTemplate>
                <sdk:HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Title}" Tag="{Binding RelativeSource={RelativeSource TemplatedParent}}"/>
                </sdk:HierarchicalDataTemplate>
            </sdk:TreeView.ItemTemplate>
        </sdk:TreeView>

后台代码如下:

 private void TreeView_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {

  e.Handled = true;

  if(myContextMenu.IsOpen)

  {

    myContextMenu.IsOpen=false;

  }
   TreeView tv = sender as TreeView;
   TextBlock tb = e.OriginalSource as TextBlock;

   if (tv != null && tb != null && tb is DependencyObject)
   {
    ContentPresenter cp = VisualTreeHelper.GetParent(tb) as ContentPresenter;

    if (cp != null && cp.Content is TreeNode)
    {
     (cp.Content as TreeNode).IsSelected = true;

     }
   }
  }

  private void TreeView_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {

    myContextMenu.IsOpen=true;

        }

 

 

public class TreeNode : NotifyBase
    {
        [XmlAttribute]
        public string Title { get; set; }

        [XmlArray]
        public List<TreeNode> Children { get; set; }

  private bool _isSelected;
  public bool IsSelected
  {
   get { return _isSelected; }
   set
   {
    if (value != _isSelected)
    {
     _isSelected = value;
     base.RaisePropertyChanged("IsSelected");
    }
   }
  }

        public TreeNode(string title)
        {
            Title = title;
            Children = null;
   IsSelected = false;
        }

        public TreeNode() : this(null) { }

    }

 

/// <summary>
    /// Class that implements a workaround for a Silverlight XAML parser
    /// limitation that prevents the following syntax from working:
    ///    &lt;Setter Property="IsSelected" Value="{Binding IsSelected}"/&gt;
    /// </summary>
    [ContentProperty("Values")]
    public class SetterValueBindingHelper
    {
        /// <summary>
        /// Optional type parameter used to specify the type of an attached
        /// DependencyProperty as an assembly-qualified name, full name, or
        /// short name.
        /// </summary>
        [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods",
            Justification = "Unambiguous in XAML.")]
        public string Type { get; set; }

        /// <summary>
        /// Property name for the normal/attached DependencyProperty on which
        /// to set the Binding.
        /// </summary>
        public string Property { get; set; }

        /// <summary>
        /// Binding to set on the specified property.
        /// </summary>
        public Binding Binding { get; set; }

        /// <summary>
        /// Collection of SetterValueBindingHelper instances to apply to the
        /// target element.
        /// </summary>
        /// <remarks>
        /// Used when multiple Bindings need to be applied to the same element.
        /// </remarks>
        public Collection<SetterValueBindingHelper> Values
        {
            get
            {
                // Defer creating collection until needed
                if (null == _values)
                {
                    _values = new Collection<SetterValueBindingHelper>();
                }
                return _values;
            }
        }
        private Collection<SetterValueBindingHelper> _values;

        /// <summary>
        /// Gets the value of the PropertyBinding attached DependencyProperty.
        /// </summary>
        /// <param name="element">Element for which to get the property.</param>
        /// <returns>Value of PropertyBinding attached DependencyProperty.</returns>
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
            Justification = "SetBinding is only available on FrameworkElement.")]
        public static SetterValueBindingHelper GetPropertyBinding(FrameworkElement element)
        {
            if (null == element)
            {
                throw new ArgumentNullException("element");
            }
            return (SetterValueBindingHelper)element.GetValue(PropertyBindingProperty);
        }

        /// <summary>
        /// Sets the value of the PropertyBinding attached DependencyProperty.
        /// </summary>
        /// <param name="element">Element on which to set the property.</param>
        /// <param name="value">Value forPropertyBinding attached DependencyProperty.</param>
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
            Justification = "SetBinding is only available on FrameworkElement.")]
        public static void SetPropertyBinding(FrameworkElement element, SetterValueBindingHelper value)
        {
            if (null == element)
            {
                throw new ArgumentNullException("element");
            }
            element.SetValue(PropertyBindingProperty, value);
        }

        /// <summary>
        /// PropertyBinding attached DependencyProperty.
        /// </summary>
        public static readonly DependencyProperty PropertyBindingProperty =
            DependencyProperty.RegisterAttached(
                "PropertyBinding",
                typeof(SetterValueBindingHelper),
                typeof(SetterValueBindingHelper),
                new PropertyMetadata(null, OnPropertyBindingPropertyChanged));

        /// <summary>
        /// Change handler for the PropertyBinding attached DependencyProperty.
        /// </summary>
        /// <param name="d">Object on which the property was changed.</param>
        /// <param name="e">Property change arguments.</param>
        private static void OnPropertyBindingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // Get/validate parameters
            var element = (FrameworkElement)d;
            var item = (SetterValueBindingHelper)(e.NewValue);

            if ((null == item.Values) || (0 == item.Values.Count))
            {
                // No children; apply the relevant binding
                ApplyBinding(element, item);
            }
            else
            {
                // Apply the bindings of each child
                foreach (var child in item.Values)
                {
                    if ((null != item.Property) || (null != item.Binding))
                    {
                        throw new ArgumentException(
                            "A SetterValueBindingHelper with Values may not have its Property or Binding set.");
                    }
                    if (0 != child.Values.Count)
                    {
                        throw new ArgumentException(
                            "Values of a SetterValueBindingHelper may not have Values themselves.");
                    }
                    ApplyBinding(element, child);
                }
            }
        }

        /// <summary>
        /// Applies the Binding represented by the SetterValueBindingHelper.
        /// </summary>
        /// <param name="element">Element to apply the Binding to.</param>
        /// <param name="item">SetterValueBindingHelper representing the Binding.</param>
        private static void ApplyBinding(FrameworkElement element, SetterValueBindingHelper item)
        {
            if ((null == item.Property) || (null == item.Binding))
            {
                throw new ArgumentException(
                    "SetterValueBindingHelper's Property and Binding must both be set to non-null values.");
            }

            // Get the type on which to set the Binding
            Type type = null;
            if (null == item.Type)
            {
                // No type specified; setting for the specified element
                type = element.GetType();
            }
            else
            {
                // Try to get the type from the type system
                type = System.Type.GetType(item.Type);
                if (null == type)
                {
                    // Search for the type in the list of assemblies
                    foreach (var assembly in AssembliesToSearch)
                    {
                        // Match on short or full name
                        type = assembly.GetTypes()
                            .Where(t => (t.FullName == item.Type) || (t.Name == item.Type))
                            .FirstOrDefault();
                        if (null != type)
                        {
                            // Found; done searching
                            break;
                        }
                    }
                    if (null == type)
                    {
                        // Unable to find the requested type anywhere
                        throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                            "Unable to access type \"{0}\". Try using an assembly qualified type name.",
                            item.Type));
                    }
                }
            }

            // Get the DependencyProperty for which to set the Binding
            DependencyProperty property = null;
            var field = type.GetField(item.Property + "Property",
                BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static);
            if (null != field)
            {
                property = field.GetValue(null) as DependencyProperty;
            }
            if (null == property)
            {
                // Unable to find the requsted property
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                    "Unable to access DependencyProperty \"{0}\" on type \"{1}\".",
                    item.Property, type.Name));
            }

            // Set the specified Binding on the specified property
            element.SetBinding(property, item.Binding);
        }

        /// <summary>
        /// Returns a stream of assemblies to search for the provided type name.
        /// </summary>
        private static IEnumerable<Assembly> AssembliesToSearch
        {
            get
            {
                // Start with the System.Windows assembly (home of all core controls)
                yield return typeof(Control).Assembly;

                // Fall back by trying each of the assemblies in the Deployment's Parts list
                foreach (var part in Deployment.Current.Parts)
                {
                    var streamResourceInfo = Application.GetResourceStream(
                        new Uri(part.Source, UriKind.Relative));
                    using (var stream = streamResourceInfo.Stream)
                    {
                        yield return part.Load(stream);
                    }
                }
            }
        }
    }

posted on 2010-10-13 00:02  小闵  阅读(3060)  评论(2编辑  收藏  举报