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;