前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >解读WPF中的Xaml

解读WPF中的Xaml

作者头像
JusterZhu
发布于 2022-12-07 12:09:39
发布于 2022-12-07 12:09:39
1.6K00
代码可运行
举报
文章被收录于专栏:JusterZhuJusterZhu
运行总次数:0
代码可运行

1.Overview

这篇文章主要分享从源代码角度解读wpf中xaml。由于源码查看起来错综复杂“随便找一个对象按下F12就是一个新的世界”,看源码的感觉就是在盗梦空间里来回穿梭;所以也是耗费很长的时间去阅读源码然后根据自己的理解编写文章和贴出部分关键源码。

2.Detail

大概将从编译、读取、加载这几个维度来解读。以防后面看源码会晕,先直接讲结果;

  • 编写(可通过vs完成)
  • 编译(可通过vs完成)
  • 读取、加载

有的帅气的观众就会问了,这些研究在实际在项目中应用场景是什么?

选择性的加载xaml(baml)文件来达到更改UI的操作。

  • 动态换肤,大家都用过手机app每到过年过节都会看到界面上会出现对应的主题,那么我们就可以在程序内设定到了某个节日直接加载对应主题界面的xaml(baml)文件来达到这种效果,对于动态皮肤场景来说,在运行时加载和解析XAML是有意义的。
  • 加载不同的.xaml(.baml)文件,以适应不同分辨率的布局
  • 简单固定的UI美工人员将设计稿转换为位图,可使用blend或者 expression design转成对应的wpf界面

还可以适配不同的业务要求。可能这种延伸就是研究的意义吧

(1)编译xaml

XAML不仅要能够解决涉及协作问题,它还需要快速运行。尽管基于XML格式可以很灵活并且很容易地迁移到其他平台和工具,但未必是有效的选择。XML的涉及目标是具有逻辑性、易读而且简单,没有被压缩。WPF 使用 BAML(Binaiy Application Markup Language,二进制应用程序标记语言)来克服这 个缺点。BAML 并非新事物,它实际上就是 XAML 的二进制表示,当在 Visual Studio 中编译 WPF 应用程序时,所有 XAML 文件都被转换为 BAML这些 BAML 然后作为资源被嵌入到最 终的 DLL 或 EXE 程序集中。BAML 是标记化的,这意味着较长的 XAML 被较短的标记替代。BAML 不仅明显小一些,还对其进行了优化,从而使它在运行时能够更快地解析。并成为一个内嵌资源;

BAML由VS编译生成存在,obj目录的debug下;

通过IL反编译项目文件之后,可以看到编译完成之后将会被连接到工程的“资源清单”当中。

使用Assembly的GetManifestResourceStream方法,可以在运行期获取到这个二进制流

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Assembly asm = Assembly.GetExecutingAssembly( );
Stream s = asm.GetManifestResourceStream("StreamName");

(2)读取、加载xaml(baml)

使用代码和未经编译的标记(XAML),这种具体方式对于某些特殊情况是很苻意义的* 例如创建高度动态化的用户界面。这种方式在运行时使用 System.Windows.Markup 名 称空间中的 从 XAML 文件中加载部分用户界面。使用代码和编译过的标记(BAML),对于 WPF 而言这是一种更好的方式,也是 Visual Studio 支持的一种方式。这种方式为每个窗口创建一个 XAML 橫板,这个 XAML 模板 被编译为 BAML,并嵌入到最终的程序集中。编译过的 BAML 在运行时被提取出来, 用于重新生成用户界面。

  • 1.当客户端程序被启动时Runtime接管代码来创建window实例
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  internal object CreateInstanceImpl(
      BindingFlags bindingAttr,
      Binder binder,
      object[] args,
      CultureInfo culture,
      object[] activationAttributes,
      ref StackCrawlMark stackMark)
    {
      this.CreateInstanceCheckThis();
      object obj = (object) null;
      try
      {
        try
        {
          if (activationAttributes != null)
            ActivationServices.PushActivationAttributes((Type) this, activationAttributes);
          if (args == null)
            args = EmptyArray<object>.Value;
          int length = args.Length;
          if (binder == null)
            binder = Type.DefaultBinder;
          if (length == 0 && (bindingAttr & BindingFlags.Public) != BindingFlags.Default && (bindingAttr & BindingFlags.Instance) != BindingFlags.Default && (this.IsGenericCOMObjectImpl() || this.IsValueType))
          {
            obj = this.CreateInstanceDefaultCtor((bindingAttr & BindingFlags.NonPublic) == BindingFlags.Default, false, true, ref stackMark);
          }
          else
          {
            ConstructorInfo[] constructors = this.GetConstructors(bindingAttr);
            List<MethodBase> methodBaseList = new List<MethodBase>(constructors.Length);
            Type[] argumentTypes = new Type[length];
            for (int index = 0; index < length; ++index)
            {
              if (args[index] != null)
                argumentTypes[index] = args[index].GetType();
            }
            for (int index = 0; index < constructors.Length; ++index)
            {
              if (RuntimeType.FilterApplyConstructorInfo((RuntimeConstructorInfo) constructors[index], bindingAttr, CallingConventions.Any, argumentTypes))
                methodBaseList.Add((MethodBase) constructors[index]);
            }
            MethodBase[] methodBaseArray = new MethodBase[methodBaseList.Count];
            methodBaseList.CopyTo(methodBaseArray);
            if (methodBaseArray != null && methodBaseArray.Length == 0)
              methodBaseArray = (MethodBase[]) null;
            if (methodBaseArray == null)
            {
              if (activationAttributes != null)
              {
                ActivationServices.PopActivationAttributes((Type) this);
                activationAttributes = (object[]) null;
              }
              throw new MissingMethodException(Environment.GetResourceString("MissingConstructor_Name", (object) this.FullName));
            }
            object state = (object) null;
            MethodBase methodBase;
            try
            {
              methodBase = binder.BindToMethod(bindingAttr, methodBaseArray, ref args, (ParameterModifier[]) null, culture, (string[]) null, out state);
            }
            catch (MissingMethodException ex)
            {
              methodBase = (MethodBase) null;
            }
            if (methodBase == (MethodBase) null)
            {
              if (activationAttributes != null)
              {
                ActivationServices.PopActivationAttributes((Type) this);
                activationAttributes = (object[]) null;
              }
              throw new MissingMethodException(Environment.GetResourceString("MissingConstructor_Name", (object) this.FullName));
            }
            if (RuntimeType.DelegateType.IsAssignableFrom(methodBase.DeclaringType))
              new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
            if (methodBase.GetParametersNoCopy().Length == 0)
            {
              if (args.Length != 0)
                throw new NotSupportedException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, Environment.GetResourceString("NotSupported_CallToVarArg")));
              obj = Activator.CreateInstance((Type) this, true);
            }
            else
            {
              obj = ((ConstructorInfo) methodBase).Invoke(bindingAttr, binder, args, culture);
              if (state != null)
                binder.ReorderArgumentArray(ref args, state);
            }
          }
        }
        finally
        {
          if (activationAttributes != null)
          {
            ActivationServices.PopActivationAttributes((Type) this);
            activationAttributes = (object[]) null;
          }
        }
      }
      catch (Exception ex)
      {
        throw;
      }
      return obj;
    }
  • 2.Window构造函数调用Application.LoadComponent读取创建.xaml(baml)

IL反编译后的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  /// <summary>
/// MainWindow
/// </summary>
public partial class MainWindow : System.Windows.Window, System.Windows.Markup.IComponentConnector {
  
  #line 10 "..\..\..\MainWindow.xaml"
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
    internal System.Windows.Controls.TextBox textBox;
    
    #line default
    #line hidden
    
    private bool _contentLoaded;
    
    /// <summary>
    /// InitializeComponent
    /// </summary>
    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "6.0.0.0")]
    public void InitializeComponent() {
        if (_contentLoaded) {
            return;
        }
        _contentLoaded = true;
        System.Uri resourceLocater = new System.Uri("/WpfApp1;component/mainwindow.xaml", System.UriKind.Relative);
        
        #line 1 "..\..\..\MainWindow.xaml"
        System.Windows.Application.LoadComponent(this, resourceLocater);
        
        #line default
        #line hidden
    }
    
    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "6.0.0.0")]
    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
    void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) {
        switch (connectionId)
        {
        case 1:
        this.textBox = ((System.Windows.Controls.TextBox)(target));
        return;
        }
        this._contentLoaded = true;
    }
}
  • 3.Application.LoadComponent()加载baml
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void LoadComponent(object component, Uri resourceLocator)
{
      if (component == null)
        throw new ArgumentNullException(nameof (component));
      if (resourceLocator == (Uri) null)
        throw new ArgumentNullException(nameof (resourceLocator));
      if (resourceLocator.OriginalString == null)
        throw new ArgumentException(SR.Get("ArgumentPropertyMustNotBeNull", (object) nameof (resourceLocator), (object) "OriginalString"));
      Uri curComponentUri = !resourceLocator.IsAbsoluteUri ? new Uri(BaseUriHelper.PackAppBaseUri, resourceLocator) : throw new ArgumentException(SR.Get("AbsoluteUriNotAllowed"));
      ParserContext parserContext = new ParserContext();
      parserContext.BaseUri = curComponentUri;
      Stream stream;
      bool closeStream;
      if (Application.IsComponentBeingLoadedFromOuterLoadBaml(curComponentUri))
      {
        NestedBamlLoadInfo nestedBamlLoadInfo = Application.s_NestedBamlLoadInfo.Peek();
        stream = nestedBamlLoadInfo.BamlStream;
        stream.Seek(0L, SeekOrigin.Begin);
        parserContext.SkipJournaledProperties = nestedBamlLoadInfo.SkipJournaledProperties;
        nestedBamlLoadInfo.BamlUri = (Uri) null;
        closeStream = false;
      }
      else
      {
        PackagePart resourceOrContentPart = Application.GetResourceOrContentPart(resourceLocator);
        ContentType contentType = new ContentType(resourceOrContentPart.ContentType);
        stream = resourceOrContentPart.GetStream();
        closeStream = true;
        if (!MimeTypeMapper.BamlMime.AreTypeAndSubTypeEqual(contentType))
          throw new Exception(SR.Get("ContentTypeNotSupported", (object) contentType));
      }
      if (!(stream is IStreamInfo streamInfo) || streamInfo.Assembly != component.GetType().Assembly)
        throw new Exception(SR.Get("UriNotMatchWithRootType", (object) component.GetType(), (object) resourceLocator));
      XamlReader.LoadBaml(stream, parserContext, component, closeStream);
}

XamlReader.LoadBaml细节代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  internal static object LoadBaml(
      Stream stream,
      ParserContext parserContext,
      object parent,
      bool closeStream)
{
      object p1 = (object) null;
      EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Event.WClientParseBamlBegin, (object) parserContext.BaseUri);
      if (TraceMarkup.IsEnabled)
        TraceMarkup.Trace(TraceEventType.Start, TraceMarkup.Load);
      try
      {
        if (stream is IStreamInfo streamInfo2)
          parserContext.StreamCreatedAssembly = streamInfo2.Assembly;
        Baml2006ReaderSettings bamlReaderSettings = XamlReader.CreateBamlReaderSettings();
        bamlReaderSettings.BaseUri = parserContext.BaseUri;
        bamlReaderSettings.LocalAssembly = streamInfo2.Assembly;
        if (bamlReaderSettings.BaseUri == (Uri) null || string.IsNullOrEmpty(bamlReaderSettings.BaseUri.ToString()))
          bamlReaderSettings.BaseUri = BaseUriHelper.PackAppBaseUri;
        Baml2006ReaderInternal baml2006ReaderInternal = new Baml2006ReaderInternal(stream, new Baml2006SchemaContext(bamlReaderSettings.LocalAssembly), bamlReaderSettings, parent);
        Type type = (Type) null;
        if (streamInfo2.Assembly != (Assembly) null)
        {
          try
          {
            type = XamlTypeMapper.GetInternalTypeHelperTypeFromAssembly(parserContext);
          }
          catch (Exception ex)
          {
            if (CriticalExceptions.IsCriticalException(ex))
              throw;
          }
        }
        if (type != (Type) null)
        {
          XamlAccessLevel xamlAccessLevel = XamlAccessLevel.AssemblyAccessTo(streamInfo2.Assembly);
          new XamlLoadPermission(xamlAccessLevel).Assert();
          try
          {
            p1 = WpfXamlLoader.LoadBaml((System.Xaml.XamlReader) baml2006ReaderInternal, parserContext.SkipJournaledProperties, parent, xamlAccessLevel, parserContext.BaseUri);
          }
          finally
          {
            CodeAccessPermission.RevertAssert();
          }
        }
        else
          p1 = WpfXamlLoader.LoadBaml((System.Xaml.XamlReader) baml2006ReaderInternal, parserContext.SkipJournaledProperties, parent, (XamlAccessLevel) null, parserContext.BaseUri);
        if (p1 is DependencyObject dependencyObject2)
          dependencyObject2.SetValue(BaseUriHelper.BaseUriProperty, (object) bamlReaderSettings.BaseUri);
        if (p1 is Application application2)
          application2.ApplicationMarkupBaseUri = XamlReader.GetBaseUri(bamlReaderSettings.BaseUri);
      }
      finally
      {
        if (TraceMarkup.IsEnabled)
          TraceMarkup.Trace(TraceEventType.Stop, TraceMarkup.Load, p1);
        EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Event.WClientParseBamlEnd, (object) parserContext.BaseUri);
        if (closeStream && stream != null)
          stream.Close();
      }
      return p1;
}
  • 4.加载控件对象

提取BAML(编译过的XAML)解析并创建每个定义的控件对象,设置属性、关联事件等内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
internal static object LoadBamlStreamWithSyncInfo(Stream stream, ParserContext pc)
{
  if (Application.s_NestedBamlLoadInfo == null)
    Application.s_NestedBamlLoadInfo = new Stack<NestedBamlLoadInfo>();
  NestedBamlLoadInfo nestedBamlLoadInfo = new NestedBamlLoadInfo(pc.BaseUri, stream, pc.SkipJournaledProperties);
  Application.s_NestedBamlLoadInfo.Push(nestedBamlLoadInfo);
  try
  {
    return XamlReader.LoadBaml(stream, pc, (object) null, true);
  }
  finally
  {
    Application.s_NestedBamlLoadInfo.Pop();
    if (Application.s_NestedBamlLoadInfo.Count == 0)
      Application.s_NestedBamlLoadInfo = (Stack<NestedBamlLoadInfo>) null;
  }
}

循环遍历所有xaml里的标签节点生成窗体内的内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static object Load(
  System.Xaml.XamlReader xamlReader,
  IXamlObjectWriterFactory writerFactory,
  bool skipJournaledProperties,
  object rootObject,
  XamlObjectWriterSettings settings,
  Uri baseUri)
{
  XamlContextStack<WpfXamlFrame> stack = new XamlContextStack<WpfXamlFrame>((Func<WpfXamlFrame>) (() => new WpfXamlFrame()));
  int persistId = 1;
  settings.AfterBeginInitHandler = (EventHandler<XamlObjectEventArgs>) ((sender, args) =>
  {
    if (EventTrace.IsEnabled(EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose))
    {
      IXamlLineInfo xamlLineInfo = xamlReader as IXamlLineInfo;
      int num1 = -1;
      int num2 = -1;
      if (xamlLineInfo != null && xamlLineInfo.HasLineInfo)
      {
        num1 = xamlLineInfo.LineNumber;
        num2 = xamlLineInfo.LinePosition;
      }
      int num3 = (int) EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientParseXamlBamlInfo, EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose, (object) (args.Instance == null ? 0L : PerfService.GetPerfElementID(args.Instance)), (object) num1, (object) num2);
    }
    if (args.Instance is UIElement instance3)
    {
      int num = persistId++;
      instance3.SetPersistId(num);
    }
    XamlSourceInfoHelper.SetXamlSourceInfo(args.Instance, args, baseUri);
    if (args.Instance is DependencyObject instance4 && stack.CurrentFrame.XmlnsDictionary != null)
    {
      XmlnsDictionary xmlnsDictionary = stack.CurrentFrame.XmlnsDictionary;
      xmlnsDictionary.Seal();
      XmlAttributeProperties.SetXmlnsDictionary(instance4, xmlnsDictionary);
    }
    stack.CurrentFrame.Instance = args.Instance;
  });
  XamlObjectWriter xamlWriter = writerFactory == null ? new XamlObjectWriter(xamlReader.SchemaContext, settings) : writerFactory.GetXamlObjectWriter(settings);
  IXamlLineInfo xamlLineInfo1 = (IXamlLineInfo) null;
  try
  {
    xamlLineInfo1 = xamlReader as IXamlLineInfo;
    IXamlLineInfoConsumer xamlLineInfoConsumer = (IXamlLineInfoConsumer) xamlWriter;
    bool shouldPassLineNumberInfo = false;
    if (xamlLineInfo1 != null && xamlLineInfo1.HasLineInfo && xamlLineInfoConsumer != null && xamlLineInfoConsumer.ShouldProvideLineInfo)
      shouldPassLineNumberInfo = true;
    IStyleConnector styleConnector = rootObject as IStyleConnector;
    WpfXamlLoader.TransformNodes(xamlReader, xamlWriter, false, skipJournaledProperties, shouldPassLineNumberInfo, xamlLineInfo1, xamlLineInfoConsumer, stack, styleConnector);
    xamlWriter.Close();
    return xamlWriter.Result;
  }
  catch (Exception ex)
  {
    if (CriticalExceptions.IsCriticalException(ex) || !XamlReader.ShouldReWrapException(ex, baseUri))
    {
      throw;
    }
    else
    {
      XamlReader.RewrapException(ex, xamlLineInfo1, baseUri);
      return (object) null;
    }
  }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Get the XAML content from an external file.
DependencyObject rootElement;
using (FileStream fs = new FileStrearn(xamlFile, FileMode Open)){
rootElement = (DependencyObject)XamlReader.Load(fs)}

// Insert the markup into this window.
this.Content = rootElement;
// Find the control with the appropriate
buttonl = (Button)LogicalTreeHelper.FindLogicalNode(rootElement, ibuttonl");
name.
// Wire up the event handler.
buttonl.Click += buttonl 'Click

【截选内容1,这一段引用lindexi文章内的内容,原文地址在文章末尾】在 WPF 中,在 XAML 里面定义的对象的创建,实际上不是完全通过反射来进行创建的,在WPF框架里面,有进行了一系列的优化。将会通过 XamlTypeInvoker 的 CreateInstance 方法来进行对象的创建,而默认的 XamlTypeInvoker 的 CreateInstance 定义如下。还有其他精彩内容在原文里可以查看;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        public virtual object CreateInstance(object[] arguments)
        {
            ThrowIfUnknown();
            if (!_xamlType.UnderlyingType.IsValueType && (arguments == null || arguments.Length == 0))
            {
                object result = DefaultCtorXamlActivator.CreateInstance(this);
                if (result != null)
                {
                    return result;
                }
            }
            return CreateInstanceWithActivator(_xamlType.UnderlyingType, arguments);
        }

        private object CreateInstanceWithActivator(Type type, object[] arguments)
        {
            return SafeReflectionInvoker.CreateInstance(type, arguments);
        }

【截选内容2,这一段引用lindexi文章内的内容,原文地址在文章末尾】

在 EnsureConstructorDelegate 方法里面将会判断如果对象是公开的,那么尝试获取默认构造函数,将默认构造函数做成委托。此时的性能将会是类型第一次进入的时候的速度比较慢,但是后续进入的时候就能使用委托创建,此时性能将会比较好。通过反射创建委托提升性能的方法,详细请看 .NET Core/Framework 创建委托以大幅度提高反射调用的性能 - walterlv

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static bool EnsureConstructorDelegate(XamlTypeInvoker type)
{
        // 如果类型初始化过构造函数创建,那么返回,这是缓存的方法
        if (type._constructorDelegate != null)
        {
               return true;
        }

         // 如果不是公开的方法,那么将无法使用反射创建委托的科技
        if (!type.IsPublic)
        {
               return false;
        }

        // 反射获取对象的构造函数
        Type underlyingType = type._xamlType.UnderlyingType.UnderlyingSystemType;
        // Look up public ctors only, for equivalence with Activator.CreateInstance
        ConstructorInfo tConstInfo = underlyingType.GetConstructor(Type.EmptyTypes);
        IntPtr constPtr = tConstInfo.MethodHandle.GetFunctionPointer();
               
        // 反射创建委托,这样下次访问就不需要使用反射,可以提升性能
        // This requires Reflection Permission
        Action<object> ctorDelegate = ctorDelegate =
                    (Action<object>)s_actionCtor.Invoke(new object[] { null, constPtr });
        type._constructorDelegate = ctorDelegate;
        return true;
}

也就是说只有第一次的类型进入才会调用反射创建委托用来提升性能,之后的进入将会使用第一次创建出来的委托来创建对象,这样能提升性能。

4.Reference

dotnet/wpf: WPF is a .NET Core UI framework for building Windows desktop applications. (github.com)

dotnet 读 WPF 源代码笔记 XAML 创建对象的方法 (lindexi.com)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JusterZhu 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
2019-1-29-多线程UI的多线程问题
详情可以参见这个大大的博客Launching a WPF Window in a Separate Thread, Part 1 : Reed Copsey, Jr.
黄腾霄
2020/06/10
8880
WPF 由于系统颜色配置 Mscms 组件损坏启动失败
本文记录 WPF 应用程序,因为系统的颜色配置 Mscms.dll 组件损坏导致应用加载图片失败,从而启动失败的原因和解决方法
林德熙
2022/08/12
5600
WPF 类型的构造函数执行符合指定的绑定约束的调用时引发了异常
本文告诉大家如果遇到类型“Foo.MainWindow”的构造函数执行符合指定的绑定约束的调用时引发了异常的时候可以如何知道是哪个不清真代码
林德熙
2019/04/22
4.9K0
dotnet 读 WPF 源代码笔记 为什么自定义的 UserControl 用户控件不能跨程序集继承
从设计上,用户控件 UserControl 就不是一个合适用来多次继承的类型,更不要说进行跨程序集继承自定义的 UserControl 用户控件。对于大部分的用户控件来说,都是采用组合现有的控件来实现的功能,本身应该被当成一个模块来进行使用。在 WPF 框架里面,从框架层阻止了开发者对自定义的 UserControl 用户控件跨程序集继承的逻辑,一旦尝试进行跨程序集继承,将在运行时抛出异常。本文将从源代码的角度告诉大家 WPF 框架是如何阻止跨程序集继承
林德熙
2022/08/12
1.1K0
WPF 源代码 资源字典 ResourceDictionary 设置 Source 属性的逻辑
本文来和大家聊聊在 WPF 里面在给 ResourceDictionary 设置 Source 属性时,在 WPF 框架里面做了哪些逻辑
林德熙
2020/11/27
2.2K0
WPF 应用启动过程同时启动多个 UI 线程且访问 ContentPresenter 可能让多个 UI 线程互等
在应用启动过程里,除了主 UI 线程之外,如果还多启动了新的 UI 线程,且此新的 UI 线程碰到 ContentPresenter 类型,那么将可能存在让新的 UI 线程和主 UI 线程互等。这是多线程安全问题,不是很好复现,即使采用 demo 的代码,也需要几千次运行才能在某些配置比较差的机器上遇到新的 UI 线程和主 UI 线程互等,应用启动失败。本文来告诉大家复现的步骤,以及原因,和解决方法
林德熙
2022/08/12
7030
WPF 应用启动过程同时启动多个 UI 线程且访问 ContentPresenter 可能让多个 UI 线程互等
CaseStudy(showcase)数据篇-Loading的制作
做silvelight也有一段时间了,相册、游戏,刚刚完成的showcase这个小程序算是一个阶段了。这里就以showcase这个项目来做一下CaseStudy。 数据篇-Loading的制作 silverlight自带了一个loading。但是由于界面的需求可能需要定制化一下。这里我的思路是做两个sl文件用其中一个去加载另外一个。也就是说有两个xap文件一个是主要的也就是你做的silverlight程序文件,另一个小的是用来做loading的。 参考文章: 技巧:在Silverlight中如何访问外部xa
用户1172164
2018/01/16
6330
用Wpf做一个可编程画板(续4-Diagram画板)
1.可编程模块,使用C#语言。2.控制台打印控件,可以打印程序中的Console.WriteLine数据 3.为了便于大家使用,写了一个Box工厂分配Box的数据流向效果图。
沙漠尽头的狼
2023/08/31
3320
用Wpf做一个可编程画板(续4-Diagram画板)
解读WPF中的Binding
基于MVVM实现一段绑定大伙都不陌生,Binding是wpf整个体系中最核心的对象之一这里就来解读一下我花了纯两周时间有哪些秘密。这里我先提出几个问题应该是大家感兴趣的,如下:
JusterZhu
2022/12/07
1.7K0
解读WPF中的Binding
动态装载和使用类型
Reflection提供诸如Microsoft Visual Basic.NET和JScript语言编译器使用的底层结构来实施隐性后绑定。绑定是定位与某一特定类型相对应的声明的过程。当这个过程发生在运行的时候,而不是编译的时候,它被称为后绑定。Visual Basic.NET使你可以在你的代码中使用隐性后绑定;VisualBasic.NET编译器调用helper 方法,使用Reflection获得对象类型。传递给helper 方法的参数 使适当的方法可以在运行时被调用。这些参数是调用方法(对象)的实例,被调用方法的名字(字符串),及传递给被调用方法的参数。(一个对象数组)。
Java架构师必看
2021/03/22
7590
WPF自学入门(一)WPF-XAML基本知识
1、XAML是派生自XML的可扩展应用程序标记语言(Extensible Application Markup Language)由微软创造应用在WPF,Silverlight等开发技术中。
黄昏前黎明后
2019/09/11
2.9K0
WPF自学入门(一)WPF-XAML基本知识
WPF 冷知识 定义依赖属性的最大数量是 65534 个
远古的 WPF 框架开发的大佬们认为没有任何业务的开发者需要用到超过 65534 个依赖属性和附加属性,为了节省内存空间就限制了所有的依赖属性和附加属性的定义总和加起来不能大于等于 65535 个
林德熙
2023/11/29
2540
【编辑】解决 Wpf TabControl 在所有选项卡上仅创建一个视图 的问题
原标题:Wpf TabControl create only one view at all tabs(https://stackoverflow.com/questions/43347266/wpf-tabcontrol-create-only-one-view-at-all-tabs)
独立观察员
2024/11/23
4530
【编辑】解决 Wpf TabControl 在所有选项卡上仅创建一个视图 的问题
[WPF]如何使用代码创建DataTemplate(或者ControlTemplate)
上一篇文章([UWP]如何使用代码创建DataTemplate(或者ControlTemplate))介绍了在UWP上的情况,这篇文章再稍微介绍在WPF上如何实现。
dino.c
2019/01/17
2.2K0
[WPF自定义控件库]了解如何自定义ItemsControl
对WPF来说ContentControl和ItemsControl是最重要的两个控件。
dino.c
2019/05/21
2.8K0
[WPF自定义控件库]了解如何自定义ItemsControl
WPF 绑定继承的样式提示 只能根据带有基类型 IFrameworkInputElement 的目标类型的 Style 样式
在 WPF 中,如果有一个样式是继承另一个样式,而样式没有使用 TargetType 那么在运行的时候会提示 只能根据带有基类型 IFrameworkInputElement 的目标类型的 Style 样式
林德熙
2022/08/12
7100
Notes on Migrating from WPF to UNO under UOS
This article documents my experience in migrating a small WPF application to the UNO framework for support on the UOS(统信).
林德熙
2023/11/28
2290
Notes on Migrating from WPF to UNO under UOS
WPF 绑定继承的样式提示 只能根据带有基类型 IFrameworkInputElement 的目标类型的 Style 样式
在 WPF 中,如果有一个样式是继承另一个样式,而样式没有使用 TargetType 那么在运行的时候会提示 只能根据带有基类型 IFrameworkInputElement 的目标类型的 Style 样式
林德熙
2020/07/28
1.2K0
WPF 表格控件 ReoGrid 的简单使用
ReoGrid 是一个开源的表格控件库,支持 Winform 和 WPF。本文演示在 WPF 中的使用,用的是直接加载 Excel 的方式,另外解决了触摸滑动的问题。
独立观察员
2022/12/06
4.3K0
WPF 表格控件 ReoGrid 的简单使用
Wpf读写Xaml文件
XamlWriter的Save函数,会将指定的对象和其属性序列化 成Xaml字符串。
Kiba518
2021/09/26
9480
Wpf读写Xaml文件
推荐阅读
相关推荐
2019-1-29-多线程UI的多线程问题
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档