WPF在不同.Net版本间的兼容性问题

第一次写博客^_^

之前在做.NET和WPF开发,期间遇到了一些.net不同版本之间兼容性问题,整理了下,留个备份。

.net 3.5的兼容性问题

1. 在.net 3.5中VirtualizingStackPanel.VirtualizationMode没有Recycling模式(是在.net 4.0后),所以用Standard替代。

    https://connect.microsoft.com/VisualStudio/feedback/details/346158/virtualizingstackpanel-virtualizationmode-not-working-properly

2. Command & CommandParameter in InputBindings are Properties not Dependency Properties,所以不能在xaml中直接用binding,解决方案自己重新实现Command和CommandParameter的类,里面定义Dependence Properties,再在xaml把相应的Command和CommanParameter定义成StaticResource reference。

New Command class:

using System;
using System.Windows;
using System.Windows.Input;

namespace Sample.WPFUI.Commands
{
    public class CommandReference : Freezable, ICommand
    {
        public CommandReference()
        {
        }

        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandReference),
                                                                                                new PropertyMetadata(new PropertyChangedCallback(OnCommandChanged)));

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        #region ICommand Members

        public bool CanExecute(object parameter)
        {
            if (Command != null)
                return Command.CanExecute(parameter);
            return false;
        }

        public void Execute(object parameter)
        {
            Command.Execute(parameter);
        }

        public event EventHandler CanExecuteChanged;

        private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CommandReference commandReference = d as CommandReference;
            ICommand oldCommand = e.OldValue as ICommand;
            ICommand newCommand = e.NewValue as ICommand;

            if (oldCommand != null)
            {
                oldCommand.CanExecuteChanged -= commandReference.CanExecuteChanged;
            }
            if (newCommand != null)
            {
                newCommand.CanExecuteChanged += commandReference.CanExecuteChanged;
            }
        }

        #endregion

        #region Freezable

        protected override Freezable CreateInstanceCore()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
View Code

New CommandParameter class:

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;

namespace Sample.WPFUI
{
    public class DataResource : Freezable
    {
        /// <summary>
        /// Identifies the <see cref="BindingTarget"/> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="BindingTarget"/> dependency property.
        /// </value>
        public static readonly DependencyProperty BindingTargetProperty = DependencyProperty.Register("BindingTarget", typeof(object), typeof(DataResource), new UIPropertyMetadata(null));

        /// <summary>
        /// Initializes a new instance of the <see cref="DataResource"/> class.
        /// </summary>
        public DataResource()
        {
        }

        /// <summary>
        /// Gets or sets the binding target.
        /// </summary>
        /// <value>The binding target.</value>
        public object BindingTarget
        {
            get { return (object)GetValue(BindingTargetProperty); }
            set { SetValue(BindingTargetProperty, value); }
        }

        /// <summary>
        /// Creates an instance of the specified type using that type's default constructor. 
        /// </summary>
        /// <returns>
        /// A reference to the newly created object.
        /// </returns>
        protected override Freezable CreateInstanceCore()
        {
            return (Freezable)Activator.CreateInstance(GetType());
        }

        /// <summary>
        /// Makes the instance a clone (deep copy) of the specified <see cref="Freezable"/>
        /// using base (non-animated) property values. 
        /// </summary>
        /// <param name="sourceFreezable">
        /// The object to clone.
        /// </param>
        protected sealed override void CloneCore(Freezable sourceFreezable)
        {
            base.CloneCore(sourceFreezable);
        }
    }

    public class DataResourceBindingExtension : MarkupExtension
    {
        private object mTargetObject;
        private object mTargetProperty;
        private DataResource mDataResouce;

        /// <summary>
        /// Gets or sets the data resource.
        /// </summary>
        /// <value>The data resource.</value>
        public DataResource DataResource
        {
            get
            {
                return mDataResouce;
            }
            set
            {
                if (mDataResouce != value)
                {
                    if (mDataResouce != null)
                    {
                        mDataResouce.Changed -= DataResource_Changed;
                    }
                    mDataResouce = value;

                    if (mDataResouce != null)
                    {
                        mDataResouce.Changed += DataResource_Changed;
                    }
                }
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DataResourceBindingExtension"/> class.
        /// </summary>
        public DataResourceBindingExtension()
        {
        }

        /// <summary>
        /// When implemented in a derived class, returns an object that is set as the value of the target property for this markup extension.
        /// </summary>
        /// <param name="serviceProvider">Object that can provide services for the markup extension.</param>
        /// <returns>
        /// The object value to set on the property where the extension is applied.
        /// </returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            IProvideValueTarget target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));

            mTargetObject = target.TargetObject;
            mTargetProperty = target.TargetProperty;

            // mTargetProperty can be null when this is called in the Designer.
            Debug.Assert(mTargetProperty != null || DesignerProperties.GetIsInDesignMode(new DependencyObject()));

            if (DataResource.BindingTarget == null && mTargetProperty != null)
            {
                PropertyInfo propInfo = mTargetProperty as PropertyInfo;
                if (propInfo != null)
                {
                    try
                    {
                        return Activator.CreateInstance(propInfo.PropertyType);
                    }
                    catch (MissingMethodException)
                    {
                        // there isn't a default constructor
                    }
                }

                DependencyProperty depProp = mTargetProperty as DependencyProperty;
                if (depProp != null)
                {
                    DependencyObject depObj = (DependencyObject)mTargetObject;
                    return depObj.GetValue(depProp);
                }
            }

            return DataResource.BindingTarget;
        }

        private void DataResource_Changed(object sender, EventArgs e)
        {
            // Ensure that the bound object is updated when DataResource changes.
            DataResource dataResource = (DataResource)sender;
            DependencyProperty depProp = mTargetProperty as DependencyProperty;

            if (depProp != null)
            {
                DependencyObject depObj = (DependencyObject)mTargetObject;
                object value = Convert(dataResource.BindingTarget, depProp.PropertyType);
                depObj.SetValue(depProp, value);
            }
            else
            {
                PropertyInfo propInfo = mTargetProperty as PropertyInfo;
                if (propInfo != null)
                {
                    object value = Convert(dataResource.BindingTarget, propInfo.PropertyType);
                    propInfo.SetValue(mTargetObject, value, new object[0]);
                }
            }
        }

        private object Convert(object obj, Type toType)
        {
            try
            {
                return System.Convert.ChangeType(obj, toType);
            }
            catch (InvalidCastException)
            {
                return obj;
            }
        }
    }
}
View Code

 Xaml sample:

<cf:CommandReference x:Key="EditTextBoxReturnCommand" Command="{Binding Path=DataContext.ViewModelCommands.EditTextBoxReturnCommand, ElementName=filePaneCloudViewPage}"/> 
<cf:CommandReference x:Key="EditTextBoxEscapeCommand" Command="{Binding Path=DataContext.ViewModelCommands.EditTextBoxEscapeCommand, ElementName=filePaneCloudViewPage}"/> 

<TextBox.Resources>
    <wpf:DataResource x:Key="EditTextBoxReturnCommandParameter" BindingTarget="{Binding Path=Content, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"/> 
    <wpf:DataResource x:Key="EditTextBoxEscapeCommandParameter" BindingTarget="{Binding ElementName=editFileNameTextBox}"/> 
</TextBox.Resources> 

<TextBox.InputBindings> 
    <KeyBinding Key="Return" CommandParameter="{StaticResource EditTextBoxReturnCommandParameter}" Command="{StaticResource EditTextBoxReturnCommand}"/> 
    <KeyBinding Key="Escape" CommandParameter="{StaticResource EditTextBoxEscapeCommandParameter}" Command="{StaticResource EditTextBoxEscapeCommand}"/>
</TextBox.InputBindings>

 

.net 4.0的兼容性问题

1. 不支持在Xaml有嵌套的template

<ListBox ItemsSource="{Binding Mylist}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <ListBox ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding}" Loaded="TextBlock_Loaded" Style="{StaticResource TextBlockStyle}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
            </ListBox>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

解决方案

1. Add the datatemplate as a StaticResource reference

<ListBox ItemsSource="{Binding Mylist}"> 
    <ListBox.ItemTemplate> 
        <DataTemplate> 
            <DataTemplate.Resources> 
                <DataTemplate x:Key="nestedDataTemplate"> 
                    <TextBlock Text="{Binding}" Loaded="TextBlock_Loaded" Style="{DynamicResource TextBlockStyle}" /> 
                </DataTemplate> 
            </DataTemplate.Resources> 
            <ListBox ItemsSource="{Binding}" ItemTemplate="{StaticResource nestedDataTemplate}"/> 
        </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

2. Use DynamicResource for the style

<TextBlock Text="{Binding}" Loaded="TextBlock_Loaded" Style="{DynamicResource TextBlockStyle}" />

转载于:https://www.cnblogs.com/trent-xu/p/6597602.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值