不使用XAML的WPF

57

从架构上看,我认为WPF非常惊人。总的来说,我是基于底层渲染/动画内部机制的忠实粉丝。模板和样式设置的灵活性令人印象深刻。

但是我讨厌XAML——我觉得它使很多事情变得复杂。我在大型和小型应用程序中使用过它,很多时候我发现自己在尝试理解一个基本原则的XAML语法时感到困惑。不仅如此,我很多次都想知道某些解析/绑定的部分有多重。 (我知道它经过编译,但我不确定有多少仍在运行时评估)

XAML只是一种构建和加载可视树的方式。是否有任何框架可以简化以非XML、基于代码(但仍然大多数采用声明式)的方式构建可视树?具体而言,我对那些减轻以下任何问题且仍保持MVVM方法的框架感兴趣:

  1. 强类型绑定。指定ViewModel必须符合特定类型。我假设BaseBinding在幕后使用反射技术,我对其速度有些怀疑,更不用说破损绑定令人烦恼了。

  2. 更快的绑定,无需INotifyPropertyChanged绑定。似乎可以创建某种BindableProperty<T>,并且绑定可以直接侦听它,而不是接收所有ViewModel属性更改。使用直接回调而不是字符串参数也似乎有优势。

  3. 另一种资源管理方法;再次,某些类型的强类型字典可能非常好用。我几乎想将样式视为lambda或类似方式以捕获强类型方面。

总之,是否有任何基于非XAML、适合MVVM且具有强类型特征的框架呢?


花一个周末学习JavaFX,不要回头看。 - sproketboy
5个回答

33

我支持你们在WPF中去除Xaml。我喜欢WPF的布局和绑定功能,但我不喜欢XAML。我希望WPF能够用纯C#编写,有以下几个好处:

  • 对象和集合初始化程序可以替代Xaml实例化。(遗憾的是xaml更倾向于自上而下而不是自下而上)。
  • 绑定转换器可以只使用lambda表达式。
  • 样式可以只是修改对象的lambda表达式,没有臃肿的<Setter>语法。
  • DataTemplates就是根据对象创建控件的lambda表达式。
  • DataTemplateSelectors就是调用其他DataTemplates的DataTemplate lambda表达式。
  • ItemsControl只需要一个接受lambda(DataTemplate)并在基础集合添加新项目时再次调用它的Foreach。
  • x:Names只是变量名。
  • 无需许多MarkupExtensions
    • x:Static
    • x:Type(特别是对于复杂的泛型!)
  • UserControls只是函数。

我认为为了使WPF可设计性而增加了过多的复杂性。Web开发已经在从FrontPage到Razor的旧日中失去了这个战斗。


5
我们对这件事的想法非常相似。我认为你可能会觉得我为其中一些想法制作的小游乐场有趣(但可能不是太有用)。我试着使用Fleck进行WebSockets通信,并在Canvas中进行简单渲染。你可以在https://bitbucket.org/jtrana/crimson/ 找到它。我已经完成了一个基本框架,具有简单的绑定、一两个基本控件和一些文本框的工作。虽然实现都很幼稚,但使用基于Lambda的绑定等仍然很有趣。只需启动项目并在Crimson/Communication中打开client.html即可。 - J Trana
1
我同意你在这里说的一切(至少,作为一个非Windows工程师理解的一切),但不幸的是,这也没有回答问题。 - Michael Scheper
我同意,XML 的主要设计目标并不是人类可读性和开发者友好性。 - BalintPogatsa

14

简化?不。但是你可以用代码实现XAML中的所有功能。例如,这里有一个简单的Windows Ink绘图应用程序 - 几乎是你能想到的最简单的应用:

who needs visual studio? green ink on purple background

没有保存,也不能更改任何内容 - 但是你可以通过代码来实现。

Sketchpad.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Ink;

public class Sketchpad : Application {

    [STAThread]
    public static void Main(){
        var app = new Sketchpad();
        Window root = new Window();
        InkCanvas inkCanvas1 = new InkCanvas();

        root.Title = "Skortchpard";

        root.ResizeMode = ResizeMode.CanResizeWithGrip;
        inkCanvas1.Background = Brushes.DarkSlateBlue;
        inkCanvas1.DefaultDrawingAttributes.Color = Colors.SpringGreen;
        inkCanvas1.DefaultDrawingAttributes.Height = 10;
        inkCanvas1.DefaultDrawingAttributes.Width = 10;

        root.Content = inkCanvas1;
        root.Show();
        app.MainWindow = root;
        app.Run();
    }

}

Sketchpad.csproj

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="15.0">
  <PropertyGroup>
    <AssemblyName>Simply Sketch</AssemblyName>
    <OutputPath>Bin\</OutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Data" />
    <Reference Include="System.Xml" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Xaml">
      <RequiredTargetFramework>4.0</RequiredTargetFramework>
    </Reference>
    <Reference Include="WindowsBase" />
    <Reference Include="PresentationCore" />
    <Reference Include="PresentationFramework" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="SketchPad.cs" />
  </ItemGroup>
  <Target Name="Build" Inputs="@(Compile)" Outputs="$(OutputPath)$(AssemblyName).exe">
    <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
    <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
  </Target>
    <Target Name="Clean">
    <Delete Files="$(OutputPath)$(AssemblyName).exe" />
  </Target>
  <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

就这些了。当然,如果你想避免使用XAML,那基本上意味着你要写大量替代的.NET代码,所以这取决于你——你是想把所有东西都倾倒在XAML中,还是宁愿用代码编写呢?

我认为在VS中进行操作的最大好处是你能够获得良好的设计支持,因此通常很容易直观地看到每个组件的位置和作用。这样做有一个额外的好处,就是你可能需要的文档查询次数会减少,并且有时还可以跳过一些步骤。

但是不使用XAML的WPF也是可行的

你甚至不需要安装Visual Studio,只需安装.NET CLI和开发人员命令提示符。将这两个文件放在一个文件夹中,然后运行msbuild,接着就可以在Bin目录下运行该文件。


7
这个问题需要链接到 Bling UI Toolkit。这是一个超级聪明的高级库,可在WPF之上为动画和丰富的UI原型设计提供支持。使用代码绑定 button.Width = 100 - slider.Value,动画效果如下:button.Left.Animate().Duration(500).To = label.Right,还有一个像素着色器编译器——令人惊叹。
不幸的是,我认为该项目已经停止开发了。但是它有很多非常聪明的想法可以借鉴。

3
没有像WPF这样的框架。你希望在WPF中有的三件事情都已经被提供了不同的组件替代了。而且,如果用你的绑定和资源系统来替换原有的系统,那么你喜欢WPF的特性(如动画、模板等)可能就无法使用,因为它们在很大程度上依赖于绑定、资源等功能。
以下是一些建议,可以改善你的体验:
1. 学会处理XAML(我以前也讨厌它,但现在我习惯了,觉得很棒)。
2. 在代码中构建自己的库,使UI的创建变得容易。毕竟,所有在XAML中完成的工作同样可以在代码中完成。
3. 如果你真的讨厌INotifyPropertyChanged,而想要一个回调函数,可以使用DependencyProperty代替。没有事件需要引发,还可以拥有回调函数和默认值!
4. 不要使用WPF。即使你说你爱它的架构,你列出的缺点/所需的“改进”几乎涵盖了它的全部。

2
> non-INotifyPropertyChanged binding.

要在您的视图模型或模型中手动实现INotifyPropertyChanged需要进行大量的手动/重复工作。但是我了解到这些替代方案
  • DynamicViewModel: 使用.NET 4.0的POCOs实现MVVM:该项目旨在提供一种使用普通CLR对象(POCOs)实现Model View ViewModel(MVVM)架构模式的方法,同时充分利用.NET 4.0 DynamicObject类。利用.NET 4.0和DynamicObject类,我们可以创建一个从DynamicObject类派生的类型,并在运行时指定动态行为。此外,我们可以在派生类型上实现INotifyPropertyChanged接口,使其成为数据绑定的良好选择。

  • Update Controls .NET:WPF和Silverlight数据绑定而无需INotifyPropertyChanged。它会自动发现依赖项,因此您不必在View Model中管理它们。并且它可以与Winforms一起使用。使用事件通过代码进行绑定。

  • notifypropertyweaver:使用IL编织(通过http://www.mono-project.com/Cecil)将INotifyPropertyChanged代码注入属性中。

    • 不需要属性
    • 不需要引用
    • 不需要基类
    • 支持.net 3.5,.net 4,Silverlight 3,Silverlight 4和Windows Phone 7
    • 支持客户端配置模式

1
很酷的项目 - 但它们都以某种方式在内部实现了INotifyPropertyChanged。我正在寻找更接近每个属性一个监听器而不是每个对象一个监听器的东西。谢谢! - J Trana

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接