第一次寫博客^_^app
以前在作.NET和WPF開發,期間遇到了一些.net不一樣版本之間兼容性問題,整理了下,留個備份。ide
.net 3.5的兼容性問題this
1. 在.net 3.5中VirtualizingStackPanel.VirtualizationMode沒有Recycling模式(是在.net 4.0後),因此用Standard替代。spa
https://connect.microsoft.com/VisualStudio/feedback/details/346158/virtualizingstackpanel-virtualizationmode-not-working-properly.net
2. Command & CommandParameter in InputBindings are Properties not Dependency Properties,因此不能在xaml中直接用binding,解決方案本身從新實現Command和CommandParameter的類,裏面定義Dependence Properties,再在xaml把相應的Command和CommanParameter定義成StaticResource reference。code
New Command class:orm
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 } }
New CommandParameter class:blog
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; } } } }
Xaml sample:ci
<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}" />