Hello World
Spiga

编写一个“绑定友好”的WPF控件

2012-05-13 23:35 by 老赵, 11124 visits

最近在搞WPF开发,这对我来说是个陌生的领域。话说回来,可能是缺少耐心的缘故,我现在学习新事物的方式主要是“看一些入门文档”,“看一些示例”,然后“猜测”其实现并摸索着使用。在很多时候这种做法问题不大,但一旦有地方猜错了,但在一段时间里似乎和实践还挺吻合的,则一旦遇到问题就会卡死。上周五我就被一个WPF绑定的问题搞得焦头烂额,虽说基本搞定,但还是想验证下是否会有更好的做法,特此记录一下,欢迎大家指正。

目标与障碍

简单地说,我想做的事情是编写一个“绑定友好”的用户控件,它可以像Telerik的RadNumericUpDown控件那样使用:

<telerik:RadNumericUpDown Value="{Binding Path=NumberValue}" />

我们可以通过控件属性的形式直接绑定一个值上去,看上去应该是最基本的要求吧?那么我们就来实现一个类似的控件,他有两个属性,一个是Text字符串属性,另一个是Number整型属性,分别交由一个文本框和一个滑动条来控制。

<UserControl>
    <Grid>
        <StackPanel>
            <TextBox Text="..." />
            <Slider Minimum="0" Maximum="100" Value="..." />
        </StackPanel>  
    </Grid>
</UserControl>

自然,MVVM是不可或缺的,因为在真实环境中一个用户控件的逻辑也会颇为复杂,我们需要对模型和界面进行分离。这个最简单的ViewModel定义如下(自然,实际情况下还需要实现INotifyPropertyChanged接口):

public class ValueInputViewModel : INotifyPropertyChanged
{
    public string Text { get; set; }

    public int Number { get; set; }
}

我之前都是使用DataContext作为ViewModel的容器,例如在BadValueInput.xaml.cs中:

public partial class BadValueInput : UserControl
{
    public BadValueInput()
    {
        InitializeComponent();

        this.DataContext = new ValueInputViewModel();
    }

    ...
}

于是便可以在BadValueInput.xaml里绑定:

<TextBox Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}" />
<Slider Minimum="0" Maximum="100" Value="{Binding Path=Number}" />

然后再定义两个依赖属性即可。接着我们在MainWindow.xaml里使用这个类,同样使用MVVM模式:创建MainWindowViewModel类型,包含MyText和MyNumber两个属性,实例化并赋值给MainWindow的DataContext,然后在XAML里绑定至BadValueInput的两个属性上:

<view:BadValueInput Text="{Binding Path=MyText}" Number="{Binding Path=MyNumber}" />

从我的设想中,这种做法没有任何问题:父控件(MainWindow)和子控件(BadValueInput)都有自身的DataContext,互不影响。父控件将自己的MyText和MyNumber分别绑定至子控件的Text和Number属性上,也符合直觉,但执行后的结果却并非如此:

System.Windows.Data Error: 40 : BindingExpression path error: 'MyText' property not found on 'object' ''ValueInputViewModel' (HashCode=6943688)'. BindingExpression:Path=MyText; DataItem='ValueInputViewModel' (HashCode=6943688); target element is 'BadValueInput' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'MyNumber' property not found on 'object' ''ValueInputViewModel' (HashCode=6943688)'. BindingExpression:Path=MyNumber; DataItem='ValueInputViewModel' (HashCode=6943688); target element is 'BadValueInput' (Name=''); target property is 'Number' (type 'Int32')

在Output窗口中出现了这样两条错误信息,意思是ValueInputViewModel上没有MyText和MyNumber两个属性。于是我就搞不懂了,为什么定义在MainWindow里的绑定使用的会是BadValueInput的DataContext,而不是当前上下文,即MainWindow的DataContext?我始终觉得这是种违反直觉的逻辑。

不使用DataContext作为ViewModel容器

我在微薄上提出这个问题之后收到了不少回应,很多朋友说是使用RelativeSource就可以解决问题,也就是让子控件可以找到父控件的DataContext,甚至说直接在子控件里直接指定父控件ViewModel路径。对于这个做法我不敢苟同,在我看来子控件应该是可以独立地自由使用的一个组件,它不应该根据父控件去调整自己的实现。

因此,即便这样的做法可以解决这一场景下的问题,但在我看来这完全属于在“凑”结果。我需要的是尽可能完善的解决方案,就像RadNumericUpDown那样干净清爽。我认为程序员还是需要一点完美主义,而不是仅仅为了解决问题而运用Workaround。

其实解决方案也很简单,@韦恩卑鄙告诉我,假如要避免出现这种情况,应该避免使用DataContext作为ViewModel容器,严格来说这是一种轻度滥用。其实只要遵循这个原则,这个问题也很容易解决。例如,在ValueInput.xaml.cs里定义个ViewModel属性:

public partial class ValueInput : UserControl
{
    public ValueInput()
        : this(new ValueInputViewModel())
    { }

    public ValueInput(ValueInputViewModel viewModel)
    {
        InitializeComponent();

        this.ViewModel = viewModel;
    }

    public static readonly DependencyProperty ViewModelProperty =
        DependencyProperty.Register("ViewModel", typeof(ValueInputViewModel), typeof(ValueInput));

    public ValueInputViewModel ViewModel
    {
        get { return (ValueInputViewModel)GetValue(ViewModelProperty); }
        set { SetValue(ViewModelProperty, value); }
    }
}

然后在ValueInput.xaml里绑定时指定特定的成员:

<UserControl x:Class="WpfUserControl.Views.ValueInput"
             x:Name="Self">
    <Grid>
        <StackPanel>
            <TextBox Text="{Binding ViewModel.Text, ElementName=Self, UpdateSourceTrigger=PropertyChanged}" />
            <Slider Minimum="0" Maximum="100" Value="{Binding ViewModel.Number, ElementName=Self}" />
        </StackPanel>
    </Grid>
</UserControl>

如今的绑定不光指定Path,还会使用ElementName将Source定义成当前控件对象。不过接下来的问题是,如何将控件的Text和Number属性,与ViewModel中的属性关联起来呢?目前我只知道使用代码来实现这种同步,这需要我们在ValueInput.xaml里添加更多代码:

public ValueInput(ValueInputViewModel viewModel)
{
    InitializeComponent();

    viewModel.PropertyChanged += (_, args) =>
    {
        if (args.PropertyName == "Text")
        {
            if (!String.Equals(viewModel.Text, this.Text))
            {
                this.Text = viewModel.Text;
            }
        }
        else if (args.PropertyName == "Number")
        {
            if (!viewModel.Number.Equals(this.Number))
            {
                this.Number = viewModel.Number;
            }
        }
    };

    this.ViewModel = viewModel;
}

public static readonly DependencyProperty TextProperty =
    DependencyProperty.Register(
        "Text",
        typeof(string),
        typeof(ValueInput),
        new FrameworkPropertyMetadata(OnTextPropertyChanged) { BindsTwoWayByDefault = true });

private static void OnTextPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
{
    var valueInput = (ValueInput)o;
    if (!String.Equals(valueInput.ViewModel.Text, valueInput.Text))
    {
        valueInput.ViewModel.Text = valueInput.Text;
    }
}

public string Text
{
    get { return (string)GetValue(TextProperty); }
    set { SetValue(TextProperty, value); }
}

public static readonly DependencyProperty NumberProperty =
    DependencyProperty.Register(
        "Number",
        typeof(int),
        typeof(ValueInput),
        new FrameworkPropertyMetadata(OnNumberPropertyChanged) { BindsTwoWayByDefault = true });

private static void OnNumberPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
{
    var valueInput = (ValueInput)o;
    if (!valueInput.ViewModel.Number.Equals(valueInput.Number))
    {
        valueInput.ViewModel.Number = valueInput.Number;
    }
}

public int Number
{
    get { return (int)GetValue(NumberProperty); }
    set { SetValue(NumberProperty, value); }
}

为了将控件上属性的改变同步至ViewModel,我们在定义依赖属性的时候提供propertyChangedCallback参数。同理,为了将ViewModel上属性的改变同步至控件,我们会监听ViewModel对象的PropertyChanged事件,这样的做法虽然麻烦,但的确管用。

如果我们要在MainWindow里使用这个控件,我们可以继续使用DataContext,此时子控件的DataContext属性会获取到父控件的DataContext对象,这自然不会出现取不到属性的问题。当然,如果父控件本身也希望成为一个独立控件的话,也可以使用同样的做法,即创建自身的ViewModel属性并使用ElementName指定Source,继续避免对DataContext产生依赖。

示例代码与疑问

本文的示例代码已存放至GitHub。我周五遇到的这个问题算是这么解决了,但其实我还是有一些疑问,例如:有没有更简单的做法?ValueInput.xaml.cs里用于同步控件属性与ViewModel属性的代码实在太多,也很容易写错。此外,能否在控件上定义一个只读的属性?例如代码中我额外添加的ReadOnlyValue依赖属性:

public static readonly DependencyProperty ReadOnlyValueProperty =
    DependencyProperty.Register("ReadOnlyValue", typeof(int), typeof(ValueInput));

public int ReadOnlyValue
{
    get { return (int)GetValue(ReadOnlyValueProperty); }
    private set { SetValue(ReadOnlyValueProperty, value); }
}

但是一旦缺少公开的setter,在XAML里就无法绑定这个属性了,即便我把绑定的Mode设为OneWayToSource。初学WPF,疑问很多,希望大家多多帮助。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

38 条回复

  1. waynebaby
    112.64.22.*
    链接

    waynebaby 2012-05-13 23:50:31

    public UserControl1()
    {
        InitializeComponent();
        Binding b = new Binding();
        b.Mode = BindingMode.TwoWay;
        b.Path = new PropertyPath ("ViewModel.MyProperty1" );
        b.Source = this;
        this.SetBinding(MyPropertyaaaaProperty, b);
    }
    
  2. waynebaby
    112.64.22.*
    链接

    waynebaby 2012-05-14 06:57:59

    关于只读属性的问题 我想了想 可不可以让控件不用dp方式创建只读属性 而用 INotifyPropertyChanged 接口呢? INPC在我印象里是轻松绑定Readonly属性的

  3. Latista
    114.250.91.*
    链接

    Latista 2012-05-14 09:31:16

    MVVM是给用Control的人准备的,而不是给写Control的人准备的。换言之,Control本身的实现中不需要有ViewModel,只需要能够绑定就可以了。所以,“绑定友好”的Control的职责是(不一定完备 :)):

    1. 提供DependencyProperty供绑定使用:例如定义Text和Number两个DP。
    2. 维护DependencyProperty与内部的基本控件的关系:例如使用ElementName/RelativeSource绑定,甚至直接在code behind中维护。
    3. 维护DependencyProperty之间的关系:例如Text和Number之间的同步。

    Control的使用者,通常是View,才会有对应的ViewModel。(View和Control之间还是有区别的)

    顺便再提两点:

    1. 可重用的Control通常实现成 CustomControl,方便Templating和Styling。UserControl就非常受限制。
    2. 实际的项目中 this.DataContext = new XxxViewModel() 的形式并不多见,通常只会在顶层View出现,而内层View/Control的DataContext往往从顶层继承,或者继承自顶层DataContext的某个属性。也会有项目采用IoC的方式对DataContext注入,不过这些都跟Control本身的实现无关了。
  4. MindHunter
    59.56.202.*
    链接

    MindHunter 2012-05-14 09:31:55

    Github上面的Sample似乎不是对应的。 另外,统一楼上的观点,这种场景可以只定义Value一个依赖属性,Text和Number实现 INotifyPropertyChanged去做。 只读属性也是如此。依赖这东西更多的是指对外部的依赖,这几个属性实现INotifyPropertyChanged就够了。

  5. 老赵
    admin
    链接

    老赵 2012-05-14 09:53:01

    @waynebaby

    XAML里只能绑定DP啊。

  6. 老赵
    admin
    链接

    老赵 2012-05-14 10:01:13

    @Latista

    不过既然Control很复杂,也需要MVVM吧,否则难写难维护啊。你说设置DataContext的形式一般只在顶层View里出现,这个的确啊,因为照这个情形也只能这样了……

  7. 老赵
    admin
    链接

    老赵 2012-05-14 10:02:34

    @MindHunter

    Sample忘了Push上去了。Value是什么?Text和Number不写成依赖属性没法绑定啊。我示例已经传上去了,要不你修改下看看?

  8. ted
    219.90.121.*
    链接

    ted 2012-05-14 11:27:40

    我在这里说几点:

    1. 对于一个独立封装的控件来讲,如果内部Hard-code了自己的DataContext是不合适的。对于外部使用者来讲,会产生强烈的误导,您刚好就是遇到了自己的情况。
    2. 我没有下载您的代码查看,我自己的理解是:对于一个UserControl,如何正确的处理其ViewModel,DependencyProperties,以及子控件属性这三者的同步关系。

    我的建议如下:

    • 不要Hardcode自己的DataContext(否则使用控件的人会很难受)
    • 首先DP与ViewModel上的属性进行双向绑定(by code)
    • 第二子控件的属性与对应的DP进行双向绑定(by xaml)

    这样的代码应该是比较简单的,希望这个信息对您有用。

  9. ted
    219.90.121.*
    链接

    ted 2012-05-14 11:31:06

    顺带说一句,Comments上面显示的时间是UTC时间,+8是北京时间,是Design吗?

  10. kw2009
    108.162.151.*
    链接

    kw2009 2012-05-14 11:41:39

    @老赵

    觉得Latista说得对。

    我知道你想把 logic 分离出来,vm 正好就是把 view logic 分离出来的,但是貌似在 control 中应用 mvvm 有些问题不是很“完美”... lol... 比如:谁是model?view model到底是谁?应该是 binding context 吧...

    mvvm 一般是将 view logic 分离出来,(我觉得)为了:

    1. 可以 unit test view logic w/o view;
    2. 一个 vm 可以给多个 view 共享 (list / chart)
    3. 可以换一套 skin, 或者 control lib,或者干脆整个 view... w/o changing vm
    4. 所以 vm doesn't know view...

    但是 control 本身再实现 vm,除了第一条符合,后面貌似都不太符合... 会不会有些 over design??

    如果 mvvm 可以,mvc 是不是也可以?反正这个 view logic 就是给这个 view 用的,vm can know and can access view... which makes mvc also make sense here, right...

  11. 老赵
    admin
    链接

    老赵 2012-05-14 14:16:23

    @kw2009

    Control不代表“简单”啊,Control只意味着是个独立单元,如果复杂的话,不还是需要MVVM嘛。

  12. 老赵
    admin
    链接

    老赵 2012-05-14 14:17:05

    @ted

    好像你说的就是我现在的做法是吗?如果觉得文章看得累的话,看看代码吧,其实也没几行。

    PS:评论时间是个bug,你也知道我懒……

  13. ted
    219.90.121.*
    链接

    ted 2012-05-14 15:00:04

    @老赵

    关于“DP与ViewModel上的属性进行双向绑定(by code)”这一点:从你文章的示例代码来看,你挂接了ViewModel的ProerptyChanged和DP的ChangedCallback函数,分别同步DP和ViewModel,这一部分是不是可以直接通过绑定搞定,那样的话代码会少很多。如下面的代码:

    this.SetBinding(DP, new Binding("Property") { Source=ViewModel, Mode= BindingMode.TwoWay });
    
  14. 老赵
    admin
    链接

    老赵 2012-05-14 15:32:32

    @ted

    嗯嗯,那就是上面 @waynebaby 说得做法咯。

  15. 链接

    airwolf2026 2012-05-14 17:46:25

    哈哈.老赵也弄wpf了.俺wpf的书还停留在两年前的进度.之后一直没有看, 当时也是看到那些绑定语法,真是烦啊...

  16. MindHunter
    59.56.202.*
    链接

    MindHunter 2012-05-14 17:55:12

    为什么定义在MainWindow里的绑定使用的会是BadValueInput的DataContext,而不是当前上下文,即MainWindow的DataContext?我始终觉得这是种违反直觉的逻辑。

    这是因为在当一个控件没有显式的设置或绑定的DataContext时,WPF会遍历整个逻辑树,直到找到一个非空的DataContext属性为止。

    你这边在BadValueInput的初始化中有设置了DataContext的值,导致它的DataContext就是设置的值。除非你此处不进行设置,才会是MainWindow的DataContext。

  17. MindHunter
    59.56.202.*
    链接

    MindHunter 2012-05-14 18:02:13

    我看得快哭了…… 这里面ValueInputViewModel和两个依赖属性Number和Text完全交杂在一起了,绑定得太坑了啊

  18. 老赵
    admin
    链接

    老赵 2012-05-14 18:15:22

    @MindHunter

    文章的意思是:我是在MainWindow里设置的绑定,为什么使用的不是MainWindow的DataContext,因此违反直觉。

    还有那个绑定,是不是用上面两位同学说的SetBinding就好了啊?

  19. MindHunter
    59.56.202.*
    链接

    MindHunter 2012-05-14 18:34:35

    这个是因为 当你有显式的设置

    this.DataContext = new ValueInputViewModel();
    

    的时候,是不会遍历逻辑树,获取MainWindow的DataContext,并设置为本身的DataContext。除非你在MainWindow再次显示的设置或者绑定DataContext。因此你在MainWindow上面绑定的不会到影响子控件。而对于

    <view:BadValueInput Text="{Binding Path=MyText}" Number="{Binding Path=MyNumber}" />
    

    这个仅仅是设置两个依赖属性的绑定,与DataContext无关。

  20. MindHunter
    59.56.202.*
    链接

    MindHunter 2012-05-14 19:19:14

    SetBinding替换界面的Text="{Binding Path=MyText}" Number="{Binding Path=MyNumber}"没有太大意义啊。这边主要的问题在于组织子控件VM、依赖属性和调用方的VM属性。子控件VM是否有必要?Latista 的组织方式比较常采用。

  21. 老赵
    admin
    链接

    老赵 2012-05-14 19:19:14

    @MindHunter

    还没听懂亚?你说的这些我在写文章的时候就明白了,我不是不知道原因,我只是说它“违反直觉”。还是那句话:凭什么写在MainWindow.xaml的标记最后加载的是子控件的DataContext啊?

    用SetBinding没太大意义吗?省了多少代码啊……还有大家都不太写稍微复杂点的子控件吗?还是不太写控件?为嘛都觉得控件不需要MVVM啊,MVVM难道不是主要看复杂不复杂么?

  22. Latista
    114.250.91.*
    链接

    Latista 2012-05-14 22:47:38

    关于不符合直觉的问题,可以换个角度理解。WPF XAML Parser无非就是做了这么几件事:

    1. 遇到一个元素(XML element)的时候,调用对应类的默认构造函数。
    2. 遇到一个属性(XML attribute)的时候(包括嵌套的属性,例如Grid.Rows),给对应的属性赋值,或者设置绑定(其实是MarkupExtension,绑定是其中的一种)
    3. 对于元素嵌套元素,则是将子元素作为值赋给父元素的Content Property(由父元素类上定义的ContentPropertyAttribute决定),这可以看作是嵌套属性的一种特殊情况。

    所以,对于任何一个元素,XAML Parser都是先构造一个默认对象,然后设置它的各属性值/绑定。基于以上的逻辑,如果控件在默认构造函数中对自己的公开属性进行了任何赋值,那么就面临着被用户覆盖的风险。例如:

    • 控件构造函数中对自己的Number属性SetBinding,是会被使用者XAML中的Number="10"或Number="{Binding MyNumber}"覆盖的。这样构造函数设置的绑定就完全没用了。
    • 控件构造函数中设置了自己的DataContext,例如this.DataContext = new MyViewModel(),也是会被使用者XAML中的 DataContext="{StaticResource AnotherViewModel}" 甚至是 DataContext="{x:Null}" 覆盖。其实这些就是最简单的.NET属性赋值,绑定可以认为是一种特殊的值。

    反过来的一个特殊情况,任何FrameworkElement的DataContext在没有明确设置值的时候,它的值不是null,也不是任意值,而是从父节点递归继承,可以认为它的初始值是一个绑定:DataContext="{Binding Parent.DataContext, RelativeSource=Self}"。一旦在构造函数中设置了 this.DataContext = new MyViewModel(),那么这个值就覆盖了初始值,自然也就不能从父节点继承了。

    至于控件需不需要ViewModel,我个人的经验是,如果硬要套MVVM模式,控件这个类本身就是最好的ViewModel,它定义的所有公开DP是可供使用的ViewModel属性,而控件内部树的组成就是它的View, View上使用TextBox、Slider等“基本控件”的DP绑定到控件上的DP。而当这个复杂控件被使用时,它本身又成为了View的一部分,它的DP又被绑定的业务逻辑的ViewModel上。

    我现在能想到的一个例子,是WPF中Expander的实现(使用了ToggleButton、ContentPresenter组成?不是很确定了)。有兴趣的话可以Reflector看一下。

    退一步讲,如果的确想在控件实现里使用ViewModel,那么这个ViewModel应该是控件的PrivateViewModel,逻辑关系应该是:TextBox/Slider的DP 绑定到 PrivateViewModel的属性Text/Number,PrivateViewModel的属性Text/Number绑定到控件本身的Text/Number DP。(注意,不能反过来,即控件本身的Text/Number DP绑定到PrivateViewModel,因为一旦这样做,使用者如果覆盖了绑定,控件就不能正常工作;使用者如果不覆盖绑定,那还用你的控件做什么?)这样一来,PrivateViewModel就必须要有“绑定”的功能,在WPF中,有绑定功能的对象就是DependencyObject了,那么与其再创建一个新的DependencyObject,纯粹为了满足MVVM pattern,倒不如直接使用控件本身这个DependencyObject。

  23. 链接

    张志敏 2012-05-15 11:41:40

    DataContext属性的设计意图就是让子控件继承父控件的数据源信息的,虽然有时也觉得不合理, 但它就是这样存在的。

  24. 老赵
    admin
    链接

    老赵 2012-05-15 17:33:25

    @张志敏

    继承没关系啊,你没看清到底是什么问题。

  25. nankezhishi
    114.80.133.*
    链接

    nankezhishi 2012-05-15 17:42:35

    Latista和MindHunter说得没错。控件是不应该自带DataContext,这样会影响使用者使用自己的VM。

    对于一个控件而言,它的首要的目的就是你说的“友好”,所以应该尽量与其它WPF控件的行为和功能一致。别的控件可以使用自己的DataContext,你自己写的控件,就也应该有这样的能力,这才是友好。

    VM是用于分层、解耦、降低复杂度没错,控件逻辑复杂了应该使用些模式什么来解决也没有错,但是不应该以控件的友好度为代价。控件内部如何解耦的,是控件自己的事情,控件的使用者不需要知道,也不应该知道,也不应该因为内部实现而影响使用者的使用方式。

    VM不是免费的。

  26. 老赵
    admin
    链接

    老赵 2012-05-15 18:11:06

    @nankezhishi

    你这看法跟我几乎完全一样……

  27. nankezhishi
    114.80.133.*
    链接

    nankezhishi 2012-05-15 18:38:26

    呃,我主要看实现方式了。想法,在标题里就说得很明确,我也很认同。

    不过,看法和做法可能就不一样了。能一次把心中所想的理念分毫不差地实现出来,那软件开发就没有重构的概念了。

    在我看来在控件中使用VM,本身引入的复杂度甚至高于VM带来的好处。如果一个控件过于复杂,拆分是一个更好的选择。ListView和DataGrid都很复杂,但是他们拆得好,复杂度就可以得以降低,同时保证控件的可扩展性和灵活度。

  28. Latista
    114.246.179.*
    链接

    Latista 2012-05-15 19:53:15

    控件内部解耦合还需要考虑的一个问题是Templating/Styling。高度可重用的控件通常都实现成custom control,这样控件的使用者可以重新定义控件的Template/Style,也就是控件的整个visual tree都可能被使用者重新定义。

    建议老赵重新用custom control的方式将这个控件实现(我假定你的目标类似于telerik的RadNumericUpDown),或许会发现更好的解决方案 :)

  29. 老赵
    admin
    链接

    老赵 2012-05-15 22:11:55

    @Latista

    嗯嗯……还在学,一点点来吧……

  30. boxsir
    66.212.31.*
    链接

    boxsir 2012-05-17 08:48:15

    TO 老赵:

    你好,我是你的博客的长期关注者之一,我很赞同你的博文中流露出的对技术的态度。根据我的了解,很多高水平的程序员都加入了创新院,而且据说盛大创新院的员工可以100%的做自己喜欢的项目,是真的吗?老赵 能否写一篇博客,介绍下创新院的工作环境和氛围。

    因为你曾经在创新院工作过,想问一个问题:

    创新院的everbox、mknote等项目偏重于应用创新,它们有可能直接带来商业价值;而JSCEX这样的基础软件则偏重于技术创新,它能够给开发者带来很大的方便,但很难直接靠它来赚钱,那么创新院对这种偏技术的创新的态度是什么?

  31. 老赵
    admin
    链接

    老赵 2012-05-17 10:52:22

    @boxsir

    很多高水平程序员都加入了创新院,也有很多离开了创新院。公司怎么可能让人100%作自己喜欢的项目呢?创新院是支持产品创新应用创新的,对Jscex这种技术创新的态度是“不支持”,当时我一进公司就提出我的一个技术上的想法和项目,结果就被领导否决了。

  32. boxsir
    58.240.31.*
    链接

    boxsir 2012-05-18 00:09:40

    @老赵:

    谢谢你的回复。有点失望,相对于应用创新,我更喜欢偏重于系统软件的技术创新。但是想想也正常,盛大毕竟是一家商业公司,必须考虑赢利的问题,创新院能够提供给程序员相对灵活自由的工作环境,就已经非常不错了。能够让程序员完全凭自己的兴趣开发软件(对工业界有帮助,但是很难赢利,如golang语言、JSCEX语言)的公司,全世界恐怕也只有google了。

  33. 老赵
    admin
    链接

    老赵 2012-05-20 12:40:39

    @boxsir

    在哪个公司,程序员都能凭兴趣自己做事,只不过是否公司支持(比如给你前,让你全职做)。要说对业界有帮助,但很难赢利,估计只有研究院了。要比研究院,Google差微软一大截。世界上只有研究院才是人类的希望,所以我一直想当科学家。

  34. xiaokang088
    122.224.131.*
    链接

    xiaokang088 2012-06-29 14:08:56

    评论很有意思! Latista 等几位解释的很透彻。

  35. waynebaby
    116.226.213.*
    链接

    waynebaby 2013-05-17 09:45:17

    话说在 MVVMSidekick 里面 一方面绑定本View的VM的时候 因为这个数量是压倒性的多 我希望所有控件不用 elementname方式 而用类似Datacontext的方式 另一方面我又希望父节点的DataContext能够用自然的方式传递过来

    我决定用ViewModel依赖属性的读写全部 指向 Page.Content.DataContext这样的方式解决

    这样一方面 Root Panel内部所有的绑定都可以自然进行 而外来的DataContext 也都可以正常的传递进来 需要绑定这个的时候再用ElementName方式

  36. xigua
    35.241.94.*
    链接

    xigua 2021-04-13 23:06:47

    福彩3D 上周五我就被一个WPF绑定的问题搞得焦头烂额,虽说基本搞定,但还是想验证下是否会有更好的做法,特此记录一下,欢迎大家指正上海快3

已自动隐藏某些不合适的评论内容(主题无关,争吵谩骂,装疯卖傻等等),如需阅读,请准备好眼药水并点此登陆后查看(如登陆后仍无法浏览请留言告知)。

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我