WPF 注意的小知识点

1、TextOptions.TextFormattingMode="Display"的目的是为了解决WPF中文字体显示模糊的问题。

2、通过storyboard动画修改控件属性后,在通过别的方式(除了storydboard外)没别的方式了,现在有3种方式解决这个问题:

方法一:将动画的 FillBehavior 属性设置为 Stop:
storyboard.FillBehavior = FillBehavior.Stop;
通过将FillBehavior设置为Stop,即通知动画在到达其活动期末尾后停止影响其目标关联属性。虽然达到了目的,但必须等待动画结束时才会生效,且更关键的是之前被storyboard修改过的所有关联属性值此时都被还原成了初始值。因此,此方法只适合用于制作类似网页中的导航菜单按钮:当鼠标悬停在菜单上时,菜单图形按钮执行一段华丽的变化动画;当鼠标移开后即变回为初始图片。

方法二:移除整个动画板(Storyboard)。此方法必须通过类似           
Leader.BeginStoryboard(storyboard, HandoffBehavior.SnapshotAndReplace, true);或
storyboard.Begin(Leader, HandoffBehavior.SnapshotAndReplace, true);
这两种方式启动动画,然后在需要解锁时通过
storyboard.Remove(Leader); storyboard = null; 通知动画板动画停止影响名为Leader对象的目标关联属性,并移除storyboard。需要特别注意的是①必须将动画的IsControllable参数设置为true;②HandoffBehavior最好设置为SnapshotAndReplace,此枚举的作用是:新动画将替换它们所应用到的关联属性上的任何现有动画。

方法三:从单个关联属性移除动画。同样的以精灵角色朝向为例,如果该属性已被Storyboard锁定,那么如果此时需要对其值进行更改,我们可以通过类似:
Leader.BeginAnimation(QXSpirit.DirectionProperty, null);或
Leader.ApplyAnimationClock(QXSpirit.DirectionProperty, null);
这两种方法来禁止关联到Leader的动画继续影响Leader的DirectionProperty关联属性(此方法对于非动画板动画也同样有效)。接着后面我们就可以轻松的通过Leader.Direction = 0 为精灵的朝向属性进行赋值并在画面中得到体现。
    以上三种解决方案在WPF中灵活的配合storyboard.Children.Clear();使用几乎可以应付任何关于Storyboard锁死关联属性的问题;但是在Silverlight中却往往不尽如人意。毕竟只是WPF的子集,在功能与方法上有着太少的支持。因此,我拓展了以下两种解决方案,更重要的,它们均为WPF/Silverlight通用的且药到病除的终极策略。

方法四:可以通过每次运行新的动画时先暂停之前的动画(注意,是暂停(Pause)而不是停止(Stop)),例如storyboard.Pause(Leader);然后再创建一个新的动画板storyboard = new Storyboard();这样,之前被storyboard修改过的关联属性目标值会被新的storyboard作为起点属性值,从而完美实现关联属性在动画与动画之间的衔接。有些朋友会问那之前的storyboard是否会继续占用内存空间?对于.net的内存回收机制我们无法控知,根据我多方查阅的资料,若您不放心,不妨在创建新的Storyboard前,通过storyboard = null 将之注销掉,在Silverlight动画中我是这样做的,实践证明此方法确实达到的目的。

方法五:以毒攻毒。既然是Storyboard锁死了我们需要更改的关联属性,那么我们同样可以通过Storyboard动画的形式来赋值更改这些关联属性。此方法乃下下策,缺点是毫无性能而言;优点是万能性:适合一切被Storyboard锁死的关联属性的修改,且无论是在WPF还是Silverlight中。下面同样以精灵的朝向为例,我们可以通过:
DoubleAnimation doubleAnimation = new DoubleAnimation();
doubleAnimation.To = direction;
doubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(10));
Storyboard.SetTarget(doubleAnimation, spirit);
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Direction"));
storyboard.Children.Add(doubleAnimation);
storyboard.Begin();
这样的动画形式对QXSpirit.DirectionProperty关联属性进行强行更改。
      本节小结:希望以上5种解锁Storyboard关联属性的解决方案能对大家的WPF/Silverlight动画开发有所帮助;同时,如果哪些地方有写得不妥或有错漏的也请大家不吝赐教,我会及时进行修改及更正。

3、WPF ScrollViewer嵌套Listbox无法滚动

最近在做项目的时候,发现listBoxzi自带的垂直滚动条有问题,经常在Add(item)的时候下面会多出一些空白的部分,而且滚动条的长度也是无规则的,一会大一会小,索性就直接在listBox外面包裹一个ScrollViewer。 
ScrollViewer中放一个listBox,可以拖动滚动条,但是滚轮上下滚动无效,后来查阅了资料找到原因,是因为listBox中自带一个滚动条,滚轮上下滚动事件应该是被截获了,而并没有传递到ScrollViewer这一层导致的,那么怎么解决呢? 
很简单,直接让listBox.Enable=false或者listBox.IsHitTextVisable=false即可,但是这样有个缺点,就是无法选择listBox中的内容了,那只能用另一个方法,代码如下:

      ListBox.PreviewMouseWheel += (sender, e) =>
           {
               var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
               eventArg.RoutedEvent = UIElement.MouseWheelEvent;
               eventArg.Source = sender;
               ListBox.RaiseEvent(eventArg);
           };

将listBox的滚动时间传递到上层,让ScrollViewer去处理即可.

4、虚拟化:

如果当前控件更改控件模板后,开启虚拟化需要启动3个属性。如:

VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
ScrollViewer.CanContentScroll="True"


如果是listbox控件,运用分组样式后开启虚拟化需要多添加一个属性VirtualizingPanel.IsVirtualizingWhenGrouping="True"。

5、调用winmm.dll进行录音时,保存的文件路径中不能有“-”;

6、a、treeview控件加载大量数据时,采用分页的形式显示;

  例如:先加载当前页面中能显示的数量,当滚动条滚动到最后时在加载同样数量的数据;

     b、wpf的treeview,如果mvvm中设置了isselected为true的时候,如果前台对应的item没有显示,即没有获得焦点,是不会触发selected事件的

7、WPF 简单的内存优化 

WPF的内存问题困扰了很久.
众所周知,如果长时间使用WPF的程序,它的内存占有将会持续增长。甚至持续的点击一个Button,它的内存也会不断的增长。这是我觉得WPF唯一不够尽人意的地方吧。
那么,难道就没有改善WPF内存的方法吗?
在网上搜索了很久,终于找到了一个比较可行的办法。
首先,感谢网友的分享:
http://www.dotnetdev.cn/2010/04/wpf内存释放解决方案/
这个方法的意思是当程序处于闲置状态时(即改程序处于未激活状态),那么我们可以通过kernel32.dll将物理内存与虚拟内存进行交换。即将主内存的资源暂时放到虚拟内存中。这样就减轻了物理内存的负担。
MSDN对这个函数的解释:
使用这个函数来设置应用程序最小和最大的运行空间,只会保留需要的内存。当应用程序被闲置或系统内存太低时,操作系统会自动调用这个机制来设置应用程序的内存。应用程序也可以使用 VirtualLock 来锁住一定范围的内存不被系统释放。
当你加大运行空间给应用程序,你能够得到的物理内存取决于系统,这会造成其他应用程序降低性能或系统总体降低性能,这也可能导致请求物理内存的操作失败,例如:建立 进程,线程,内核池,就必须小心的使用该函数。
实际上,这个函数并不能真正的释放内存,而只是重新分配改程序的内存占用,将暂时不需要的内容放进虚拟内存,当应用程序重新激活时,会将虚拟内存的内容重新加载到内存。所以,我们不宜过度频繁的调用该方法,这样只会使性能变低。
实际使用中,我们只需要当窗口关闭时,或者最小化时调用此方法即可解决内存不能释放的问题,该方法同样适用于Silverlight和Winform。
        [DllImport("kernel32.dll")] public static extern int SetProcessWorkingSetSize(IntPtr proc, int min, int max);
        protected override void OnDeactivated(EventArgs e)
        {
            base.OnDeactivated(e);
            SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);
        }
 
补充:后来发现也可以通过限制程序的使用内存进行优化。但是这需要知晓程序的最大内存占有。
        int maxWorkingSet = 1024000;
        public static void SetWorkingSet(int maxWorkingSet)
        {
            IntPtr min = System.Diagnostics.Process.GetCurrentProcess().MinWorkingSet;
            try
            {
                System.Diagnostics.Process.GetCurrentProcess().MaxWorkingSet = (IntPtr)maxWorkingSet;
            }
            catch ()
            {
                System.Diagnostics.Process.GetCurrentProcess().MaxWorkingSet = min;
            }
        }
 private void Window_Deactivated(object sender, EventArgs e)
        {
            try
            {
                SetWorkingSet(maxWorkingSet);
            }
            catch ()
            {
            }
        }

8、WPF xmal标记扩展(MarkupExtension)

为实现标记扩展,我们还需要实现MarkupExtension类的ProvideValue方法。

9、ObservableCollection集合加载大量数据时很慢,而且大量数据清理时也很慢;

   加载大量数据时,集合尽量用List集合,性能比较稳定且速度快;

10、列表测试数据快速生成 

   Enumerable.Range(0, 100).Select(i => new { Id = i, Name = "Name - " + i });

11、后台设置宽度为 * 号

   DataGridLength length=new DataGridLength(1,DataGridLengthUnitType.Star);
   lastColumn.Width = length;

12、Slider高亮一段区域 SelectionStart="10"  SelectionEnd="40" Minimum="0" Maximum="100" Value="50"  IsSelectionRangeEnabled="True"

13、Color color = new Color();
            //设置为红色
            color = Color.FromRgb(255, 0, 0);
            //设置为半透明的红色
            color = Color.FromArgb(100, 255, 0, 0);
            //通过字符串方式为颜色赋值,字符串格式为"#aarrggbb".前两位为透明度A,后面依次为R,G,B,并且需要十六进制数值表示
            color = (Color)ColorConverter.ConvertFromString("#FFFF0000");

14、WPF的按钮,默认没有MouseDown和MouseUp,需要自己手动加

  r1.AddHandler(Button.MouseDownEvent, new RoutedEventHandler(r1_MouseDown), true);
                             r1.AddHandler(Button.MouseUpEvent, new RoutedEventHandler(r1_MouseUp), true);

15、当原控件的某个属性有问题满足不了需求,属性重写

      static AyTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(AyTextBox), new FrameworkPropertyMetadata(typeof(AyTextBox)));

            TextProperty.OverrideMetadata(
                typeof(AyTextBox),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(TextPropertyChanged)));
        }

16、 [前台方式]对于前台演示demo  需要反射枚举,你可以这样做

引入   xmlns:system="clr-namespace:System;assembly=mscorlib"    

ObjectDataProvider x:Key="placementEnum" MethodName="GetValues" ObjectType="{x:Type System:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="PlacementMode"/>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>

<ComboBox x:Name="placementSelector" ItemsSource="{Binding Source={StaticResource placementEnum}}" IsSynchronizedWithCurrentItem="True" Width="100"  SelectedIndex="2" HorizontalAlignment="Left"/>

17、自定义控件 ,标记某些style只能用于某个类型
[StyleTypedPropertyAttribute(Property = "ItemContainerStyle", StyleTargetType = typeof(ListViewItem))]
public class ListView : ListBox

18、附加 事件后台代码

 public AyTreeView()
        {
            this.AddHandler(TreeViewItem.ExpandedEvent, new RoutedEventHandler(AyTreeViewItemExpanded)); 
        }

        private void AyTreeViewItemExpanded(object sender, RoutedEventArgs e)
        {
            TreeViewItem tvi = e.OriginalSource as TreeViewItem;
            if (tvi != null)
            {
                AyMessageBox.ShowInformation(string.Format("TreeNode '{0}' was expanded", tvi.Header));
            }
        }

19、获得句柄
窗体: 
IntPtr hwnd = new WindowInteropHelper(this).Handle;

控件: 
IntPtr hwnd = ((HwndSource)PresentationSource.FromVisual(uielement)).Handle;

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值