专注收集记录技术开发学习笔记、技术难点、解决方案
网站信息搜索 >> 请输入关键词:
您当前的位置: 首页 > WinRT Metro

WinRT ListView间距变色(二)

发布时间:2011-06-23 13:56:00 文章来源:www.iduyao.cn 采编人员:星星草
WinRT ListView间隔变色(二)

上文说到,WinRt中,我们不能在Style的Setter使用Binding.这个问题其实从SL5之前,一直都不可以。但是,为了使用强大的Binding,人们也一直想使用各种方法来达到Binding

从茫茫的Web里找一个有用的东西,本来是很简单的一件事,但是,MS最近几年,经常自我革新,革自己的命,经常今天可以用的技术,明天换个名字,少点东西,就出来让万千小白来试了。从WPF/SL/WinRT一样的Xaml却不一样的精彩。我们常常想,要是WinRT的Xmal也如WPF的那么强大就好了。但这也是只是想想而已。

言归正传

在SL时代,我们参看的一般是这一文章

The taming of the phone [New SetterValueBindingHelper sample demonstrates its usefulness on Windows Phone 7 (and Silverlight 4)]

在WinRT时代,我们借助于SO,找到这个

WinRT : Simple ScheduleControl

另外还一个C++/DX用的

WinRT and C++/CX compatible way to set Bindings via Styles

在这里我们找到一直以来想要的一个帮助类SetterValueBindingHelper.

如下:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Markup;

namespace SLWeek.Utils
{
    [ContentProperty(Name = "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;
            TypeInfo typeInfo = null;
            if (null == item.Type)
            {
                // No type specified; setting for the specified element
                type = element.GetType();
                typeInfo = type.GetTypeInfo();
            }
            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
                        typeInfo = assembly.DefinedTypes
                            .Where(t => (t.FullName == item.Type) || (t.Name == item.Type))
                            .FirstOrDefault();
                        if (null != typeInfo)
                        {
                            // Found; done searching
                            break;
                        }
                    }
                    if (null == typeInfo)
                    {
                        // 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));
                    }
                }
                else
                {
                    typeInfo = type.GetTypeInfo();
                }
            }

            // Get the DependencyProperty for which to set the Binding
            DependencyProperty property = null;
            var field = typeInfo.GetDeclaredProperty(item.Property + "Property"); // type.GetRuntimeField(item.Property + "Property");
            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(Windows.UI.Xaml.Controls.Control).GetTypeInfo().Assembly;
            }
        }
    }
}
View Code


在这里我们要注册一点:

1  var field = typeInfo.GetDeclaredProperty(item.Property + "Property"); 

我们要清楚,依赖属性的问题,我们当前的typeInfo,他可能有的DeclaredProperty,很多是从基类继承过来的。所以,我们在使用的时候,在Xmal中设定SetterValueBindingHelper的Type是,一定要设定为基类。要不,就不能正常获得依赖属性


 

我们解决了Setter不能Binding的问题。

接下来,就完成间隔变色的问题

我们先要实现一个Conveter

 1 public  sealed class ListItemBackgroudConverter:IValueConverter
 2     {
 3         public SolidColorBrush OddColorBrush { get; set; }
 4         public SolidColorBrush EvenColorBrush { get; set; }
 5         public object Convert(object value, Type targetType, object parameter, string language)
 6        {
 7            var item = value as ListViewItem;
 8            if (item != null)
 9            {
10                 var listView = ItemsControl.ItemsControlFromItemContainer(item);
11                if (listView != null)
12                {
13                    var index = listView.IndexFromContainer(item);
14                    return index % 2 == 0 ? EvenColorBrush : OddColorBrush;
15                }
16            }
17 
18            return null;
19        }
20 
21        public object ConvertBack(object value, Type targetType, object parameter, string language)
22        {
23            throw new NotImplementedException();
24        }
25     }

这个是我们的老套路了,为了方便在XMAL设定间隔色,我们定义了两种Brush

接下来,我们来定义Convetert和ListItem的ItemContainerStyle

 

 <converter:ListItemBackgroudConverter x:Key="ListItemBackgroudConverter"  OddColorBrush="{StaticResource SilverColorBrush}" EvenColorBrush="{StaticResource AsbestosColorBrush}"/>

 

 <Style x:Key="ListItemBackgroud" TargetType="ListViewItem">
        <Setter Property="utils:SetterValueBindingHelper.PropertyBinding">
            <Setter.Value>
                <utils:SetterValueBindingHelper Type="Control" Property="Background" Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource ListItemBackgroudConverter}}"/>
            </Setter.Value>
        </Setter>
 </Style>

再一次提醒注意,这里的Type是Control,而不是ListViewItem,因为只有Control的DeclaredProperty才有Backgroud.

我们在页面应用下这个Style

   <ListView ItemsSource="{Binding ListPostTypes,Mode=TwoWay}" ItemContainerStyle="{StaticResource ListItemBackgroud}" Style="{StaticResource ListViewWrapItemsPanel}" ItemTemplate="{StaticResource SelectChannelTypeDataTemplate}"/>

 

最后,我们看下效果:

 

 

由于我ListView的Style对ListView的容器进行了更改,换成了ItemsWrapGrid,所以,它会自动根据宽度进行排列

其Style为

 <Style x:Key="ListViewWrapItemsPanel" TargetType="ListView">
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <ItemsWrapGrid  Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
</Style>

 

 


 

友情提示:
信息收集于互联网,如果您发现错误或造成侵权,请及时通知本站更正或删除,具体联系方式见页面底部联系我们,谢谢。

其他相似内容:

热门推荐: