随笔-10  评论-42  文章-1  trackbacks-0
  2008年9月8日
     摘要: 在贴出来上一篇文章后,感觉那个ColorPicker太简单了,于是决定搞个Blend中的那种ColorPicker。由于工作量比较大,所以打算分成几次来完成。  首先说明一下,这个Demo还是属于未完成的阶段,比如ColorPicker的属性只是简单地设置了一个SelectedColor属性,而实际上分为A,R,G,B四个属性比较合适,这样可以在右边直接修改值;又比如,样式实在... 阅读全文
posted @ 2008-09-08 16:37 智者千虑 阅读(674) | 评论 (5)编辑
  2008年9月3日

斯克迪亚看到一篇WPF动态改变主题颜色的文章,来了兴趣,于是自己搞了个简单的ColorPicker控件。

 

控件其实很简单,定义了5个依赖属性 

FinalBrushProperty, AProperty, RProperty, GProperty, BProperty

然后当A,R,G,B发生变化时,构造新的FinalBrush

在FinalBrush发生变化时,更新ARGB的值。

 

Code

 

在ColorPicker的模板里面,分别放置4个Slider绑定到ARGB,一个Border绑定到FinalBrush以预览结果。

 

 

Code

 

这个时候,ColorPicker就可以使用了。在Demo里面,我做了一个ColorPickerDialog。它继承自Window,里面放了一个ColorPicker控件,然后将它的FinalBrush属性绑定到资源中的WindowBackground上。这样打开Dialog的时候,它的颜色自动和资源的颜色同步。同时,监听它的ColorPicker的FinalBrushChanged事件,更新资源中的颜色。这样,当我们调节ColorPickerDialog的颜色的时候,Window的颜色同步变化。

当然,你可以做的更完善,比如添加一个确定和取消按钮,当取消的时候恢复原来的颜色。或者放一个CheckBox,指定是否同步预览。

我的美工功底比斯克迪亚差远了,呵呵,就是原始的样式。

源代码下载:http://files.cnblogs.com/RMay/ChangeColor.rar

 

晕啊,用Chrome编辑有问题。

 

posted @ 2008-09-03 17:14 智者千虑 阅读(1135) | 评论 (4)编辑
  2008年8月29日
     摘要: 【重要】代码有误,我已经更新了可能有时候会有这样的需求,我们的应用程序需要弹出一个窗口,或者是包含多个窗口。同时呢,又不想真正的用Window,尤其是当我们写XBAP应用的时候。恰巧WPF里面又没有MDI…… 当然,我们有几种解决办法。 一种比较简单的办法是,用UserControl仿造一个窗口放在应用程序里面,然后将Visibility设置为隐藏。接着,在我们需要的时候,... 阅读全文
posted @ 2008-08-29 12:39 智者千虑 阅读(1378) | 评论 (10)编辑
  2008年8月22日
     摘要: 最近做控件上了瘾,现在把做的一个类似于QQ面板的控件放上来。【分析】从整体来看,这个控件应该同ListBox,ListView这类控件一样,是一个ItemsControl,而中间的项,就是它的Item。因此,为了完成一个这样的控件,至少需要两个东西:GroupShelf:也就是充当容器角色的控件GroupShelfItem:即这个控件中的项其中,GroupShelf需要保证某项的展开同时,其他项被... 阅读全文
posted @ 2008-08-22 11:50 智者千虑 阅读(2558) | 评论 (17)编辑
  2008年8月14日
     摘要: 英文原文地址:Simplifying the WPF TreeView by Using the ViewModel Pattern作者:Josh Smith文中代码的下载地址:http://www.codeproject.com/KB/WPF/TreeViewWithViewModel/TreeViewWithViewModelDemo.zip好像需要登录才能下载,我放一个上来吧http://f... 阅读全文
posted @ 2008-08-14 16:43 智者千虑 阅读(182) | 评论 (3)编辑
  2008年7月28日

修改:经过研究,发现只要在Frame上设置JournalEntry.KeepAlive="True"就可以使用第一种绑定到Source的最简单的办法来实现文中的效果。不用自己管理Page

 

这几天给给别人做了几个Demo,但觉得每个Demo都做一个工程太麻烦,不好管理,于是决定把每个Demo都各自用Page,然后通过一个列表,可以选择各个页面来查看。就如下图的效果:

 

当从左边选中一项后,右边的Frame会展示相应的内容。

我采用了一个xml文件来描述相关的信息,示例如下:

 

<?xml version="1.0" encoding="utf-8" ?>
<Pages>
  
<Page Name="Page1" Uri="/FrameContent;Component/Page1.xaml"/>
  
<Page Name="Page2" Uri="/FrameContent;Component/Page2.xaml"/>
</Pages>

这是一个非常简单的描述,每个Page项描述这个Page的Name和对应的xaml文件,然后我们可以简单用下面的方式来绑定这些信息来达到目的:

 

<ListBox x:Name="ListBox1"
          ItemsSource
="{Binding Source={StaticResource ListSource}}" 
          DisplayMemberPath
="@Name"/>
<!-- 最简单的方式就是用Frame的Source来做绑定,不过这样会导致每次都生成新的实例 -->
<Frame DataContext="{Binding ElementName=ListBox1, Path=SelectedItem}" 
       Source
="{Binding XPath=@Uri}"/>

 

不过,这样有一个小小的问题在于,每次我切换Page的时候,都将重新生成一个Page的实例,以前在Page上做的一些操作会消失。这不是我想要的,我希望有一个类似于PagePool的东西来缓存我这些创建好的页面,这样在切换的时候会减少创建实例的开销,同时可以保证无论怎么切换始终是同一个Page的实例。于是我做了如下的更改:

 

<ListBox x:Name="ListBox1"
         ItemsSource
="{Binding Source={StaticResource ListSource}}" 
         DisplayMemberPath
="@Name"/>
<Frame x:Name="PageHost1"
       NavigationUIVisibility
="Hidden"
       Content
="{Binding ElementName=ListBox1, Path=SelectedItem, Converter={StaticResource Converter}}"/>

 

我直接把Frame的Content属性绑定到选中的项上,并且用一个Converter来返回Page的实例,在Converter里面,我用一个Dictionary来保存创建过的页面,保证它们只会被创建一次:

 

public class FrameContentConverter : IValueConverter
    
{
        
// 使用Page池来减少创建Page的开销
        private Dictionary<string, Page> _pagePool = new Dictionary<string, Page>();

        
IValueConverter Members
    }

 

理论上来说,这应该工作良好,然而,实际上却发生一点小小的意外:

Frame展示的内容只跟第一次选中的项有关,其后无论如何切换,Frame的内容均不受影响

难道是Frame的Content属性默认是以OneTime的模式来绑定的?于是我显示地指定Mode=OneWay,结果依然如此。

莫非Frame的Content属性只能指定一次?好吧,既然正着来不行,那我就试试反着的。

索性,我把ListBox的SeletedItem使用OneWayToSource的模式绑定到Frame的Content属性上。当然,这种情况下,FrameContentConverter里面的ConvertBack方法需要实现。

 

<ListBox x:Name="ListBox2" 
         ItemsSource
="{Binding Source={StaticResource ListSource}}"
         DisplayMemberPath
="@Name"
         SelectedItem
="{Binding ElementName=PageHost2, Path=Content, Converter={StaticResource Converter}, Mode=OneWayToSource}"/>
<Frame x:Name="PageHost2" NavigationUIVisibility="Hidden"/>

 

采用这种方式后,一切正常了:

 

这说明,Frame的Content属性不是只能设置一次的,只是在对Frame的Content属性做绑定时,由于某种未知的原因,无法对数据源的变化产生响应,鉴于我目前的系统是Vista SP1,上次的Frame出现了渲染上的问题,这次我也没有找没装SP1的机子做测试,所以我并不能确定这是WPF本身的BUG还是sp1引起的问题,还是我某个地方没有弄好造成的。

做了一个对比的示例,有兴趣的读者可以下载回去看看。http://files.cnblogs.com/RMay/FrameContent.rar

posted @ 2008-07-28 10:39 智者千虑 阅读(986) | 评论 (2)编辑
  2008年7月22日

这几天一直有人问我如何保存RichTextBox的文本到数据库,包括格式等等,然后需要的再从数据库取出来,并且显示到RichTextBox中。

其实,RichTextBox的文本是一个FlowDocument类型的对象,我们只需要利用XamlReader和XamlWriter就能很好的完成上述工作。

 

【保存Document到流】

FlowDocument document = richTextBox.Document;

Stream s = new MemoryStream();  // 其他的什么Stream类型都没问题
XamlWriter.Save(document, s);

// 拿到s之后,再转化成二进制数据写到数据库就OK了

byte[] data = new byte[s.Length];

s.Position = 0;

s.Read(byte, 0, s.Length);

s.Close();

// 拿着data干啥都行

// ……

 

【从数据库中读取】

// data是从数据库中读出来的二进制数据

Stream s = new MemoryStream(data);

FlowDocument doc = XamlReader.Load(s) as FlowDocument;
s.Close();
richTextBox.Document = doc;

 

PS:有人问过我如何对RichTextBox的Document属性做绑定,由于RichTextBox的Document属性不是一个DependencyProperty,

所以我采用的是继承RichTextBox,自己定义一个BindableDocument的DependencyProperty来做。

    public class BindableRichTextBox : RichTextBox
    
{
        
public FlowDocument BindableDocument
        
{
            
get return (FlowDocument)GetValue(TextProperty); }
            
set { SetValue(TextProperty, value); }
        }


        
// Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register(
"BindableDocument"typeof(FlowDocument), typeof(BindableRichTextBox), new UIPropertyMetadata(nullnew PropertyChangedCallback(OnTextPropertyChanged)));

        
private static void OnTextPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        
{
            BindableRichTextBox textBox 
= sender as BindableRichTextBox;
            
if (textBox != null)
            
{
                textBox._changeFromBinding 
= true;
                textBox.OnTextPropertyChanged(e);                
            }

        }


        
// 防止死锁,比如A变了通知B,B变了又通知A
        private bool _changeFromBinding = false;

        
// 当BindableDocument属性变化时,通知Document属性
        protected virtual void OnTextPropertyChanged(DependencyPropertyChangedEventArgs e)
        
{
            
if (_changeFromBinding)
            
{
                
this.Document = e.NewValue as FlowDocument;
            }

        }


        
// 当Document属性变化时,通知BindableDocument属性
        protected override void OnTextChanged(TextChangedEventArgs e)
        
{
            
base.OnTextChanged(e);
            
if (!_changeFromBinding)
            
{               
                
this.BindableDocument = this.Document;
            }

            
// 放到外面
            _changeFromBinding = false;
        }

    }

 

做了个小程序,绑定了一个TextBox的Text到RichTextBox。 下载

 

 

 

posted @ 2008-07-22 17:33 智者千虑 阅读(1102) | 评论 (1)编辑
  2008年7月16日
今天刚刚升级了Vista SP1,发现一个有意思的问题。

这个程序使用了将Aero特效扩展到整个ClientArea的代码(参见:http://www.cnblogs.com/zhouyinhui/archive/2007/09/08/886724.html
下面的释义显示部分使用了一个Frame控件。
在未安装SP1之前,程序运行良好,在上面给出的链接中有效果图,在安装之后,Frame控件中的字变得透明了。
这个是非WPF方式绘制才会出现的现象。

看来大家在装sp1之前要谨慎啊

继续探究中……
posted @ 2008-07-16 15:02 智者千虑 阅读(231) | 评论 (0)编辑
  2008年7月1日

Command

Name

Description

F i

FillRule

i=0:EvenOdd.

i=1:NonZero.

M x y

Move

Moveto (x, y).

m x y

Relative move

Moveto (x0+x, y0+y).

L x y

Line

Drawline to (x, y).

l x y

Relative line

Drawline to (x0+x, y0+y).

H x

Horizontal line

Drawline to (x, y0).

h x

Relative horizontal line

Drawline to (x0+x, y0).

V y

Vertical line

Drawline to (x0, y).

v y

Relative vertical line

Drawline to (x0, y0+y).

A xr yr a i j x y

Arc

Drawarc to (x, y) based on ellipse with radii (xr,yr) rotated a degrees. i=1:IsLargeArc. j=1: Clockwise.

a xr yr a i j x y

Relative arc

Drawarc to (x0+x, y0+y).

C x1 y1 x2y2 x3 y3

CubicBézier

DrawBézier to (x3, y3) withcontrol points (x1, y1) and (x2, y2).

c x1 y1 x2y2 x3 y3

Relative cubic Bézier

DrawBézier to (x0+x3,y0+y3) with control points (x0+x1, y0+y1) and (x0+x2, y0+y2).

S x2 y2 x3 y3

Smooth cubic Bézier

DrawBézier to (x3, y3) with reflected control point and (x2, y2).

s x2 y2 x3y3

Relative smooth cubic Bézier

DrawBézier to (x0+x3,y0+y3) with reflected control point and (x0+x2, y0+y2).

Q x1 y1 x2y2

Quadratic Bézier

Drawquadratic Bézier to (x2, y2)with control point (x1, y1).

q x1 y1 x2y2

Relative quadratic Bézier

Drawquadratic Bézier to (x0+x2,y0+y2) with control point(x0+x1, y0+y1).

Z

z

Closefigure

 

From: 《Application = Code + Markup : A Guide to the Microsoft Windows Presentation Foundation》 by Charles Petzold

posted @ 2008-07-01 15:02 智者千虑 阅读(59) | 评论 (0)编辑
  2008年6月30日
 

MeshGeometry3DNormals属性和TextureCoordinates属性用于指定纹理如何贴到3D模型的表面去。


<MeshGeometry3D Positions="1,1,0 -1,1,0 -1,-1,0 1,-1,0"  

                                 Normals="0 0 1, 0 0 1, 0 0 1, 0 0 1"

                                 TextureCoordinates="1 0, 0 0, 0 1, 1 1"

                                 TriangleIndices="0,1,3 3,1,2"/>

上面的代码建立了一个简单的平面模型。

 

MSDN:Normal vectors are vectors perpendicular to the face of each triangle that defines a mesh. Normals determine whether a given triangle face is lit.Normals决定了一个给定的三角面是否被照亮)

MSDN:Texture coordinates determine how a Material is mapped to the vertices of the triangles that make up a mesh. TextureCoordinates决定了材质如何被映射到构成网格的三角形的顶点)


对于一个材质来说,它的顶点定义如下:

 

上面的代码: TextureCoordinates="1 0, 0 0, 0 1, 1 1"也就是说,将M1映射