初学者 - 对WPF中的绑定和资源感到困惑

7 浏览
0 Comments

初学者 - 对WPF中的绑定和资源感到困惑

我正在尝试学习WPF,但我发现很难理解绑定,\"资源\"和对象创建。

我的背景是C++ / MFC和C# -Winforms。

我的问题:

  1. 我在XAML中看到的大多数示例(在MSDN和我阅读过的其他两本WPF书籍中)在绑定表达式中使用StaticResource。这些与静态成员有任何关系吗? 还是这只是一个误导人的名称? 当将任何对象引用定义为StaticResource时,何时实例化?
  2. 就我所看到的而言,StaticResources与“Resources”部分中定义的“things”一起使用。例如:app / window / control等等。现在,这些资源部分对我来说非常困惑。它们究竟是什么? 根据我在MFC中的经验,它们是图标,字符串等。但是,根据我所看到的所有示例,在WPF中,它们似乎本质上是\"倒垃圾场\" 用于标记中的所有种类的全局对象定义(样式、数据模板等)和标记中的所有种类的全局对象实例化。我正确吗? 这让我感到非常凌乱。

    它实际上涉及在XAML中学习各种半-DSL(用于定义样式,定义数据模板,创建对象等),并将它们都粘在同一个地方。我一直在考虑像手动编辑MFC中的资源文件(.rc)之类的东西。 至少那里部分是分离的,每种资源的语法相对简单。

  3. 为了解决前面两个问题:当我在资源部分定义一个对象实例,并稍后从StaticResource绑定中引用它时,它何时被实例化?

    MSDN说(在\"How to:Make Data Available for Binding in XAML\"中):

使对象可用于绑定的一种方法是将其定义为资源

然而,这并不是很清楚。他们所说的“可用”是什么意思?是创建了对象吗?是连接到绑定子系统吗?那么这个对象到底是何时被创建的呢?

通过玩弄一个简单的例子,我发现当WPF试图附加绑定时,它似乎会自动为我创建这个对象。这更令人困惑。

编辑:

根据下面karmicpuppet的说明,我仍然不明白这与绑定机制有什么关系。

假设我在资源中有:

 

(其中Person是一个具有属性名称的类),然后在窗口中我有:

 

1)这是做什么用的?它是否经过相同的步骤 - 搜索资源,然后将其应用于Text属性?MyPerson对象是在窗口创建时还是之后创建的?

2)我是否必须使用绑定机制绑定到Name属性?我不能像你上面使用myBrush那样直接绑定它吗?为什么我不能像这样做呢?

 

这是框架的短视吗?我觉得我在这里遗漏了非常重要的东西,但我似乎无法理解是什么...

3)我尝试使用DynamicResource,但是我对自己采取的每一步都感到非常困惑。

a)在我的单个窗口类上面添加了一个DependencyObject及其DependencyProperty(这个DependencyObject是必需的吗?)

public class SomeText : DependencyObject
{
    public string Header
    {
        get { return (string)GetValue(HeaderProperty); }
        set { SetValue(HeaderProperty, value); }
    }
    public static readonly DependencyProperty HeaderProperty =
        DependencyProperty.Register("Header", typeof(string), typeof(SomeText), new UIPropertyMetadata(0));
}

b)将其实例添加到Windows.Resources中(使用DynamicResource是否必要?MSDN似乎说不是,但如果是,我无法弄清楚如何在XAML中执行下一步)

c) 我尝试了这两种方式:

Text="{Binding Source={DynamicResource HeaderText}, Path=Header}"

这使我遇到了一个异常,还有

Text="{DynamicResource HeaderText}"

但我不明白应该把路径放在头部属性的哪里。

这是我最近尝试调整WPF的第5次或更多次,每次我都被这些看似简单的问题所困扰。我读了两本书,真的试图理解MSDN的文章,但它们并没有任何帮助。

admin 更改状态以发布 2023年5月21日
0
0 Comments

把它想象成这样:所有的FrameworkElements(窗口、按钮、其他控件等)以及Application对象都包含一个资源字典。每当你在XAML中定义一个资源,就像这样:\n


  
    
    
      
    
  

\n就像在代码中做这样的事情:\n

class Window
{
  void Window()
  {
    this.Resources.Add("myBrush", new SolidColorBrush(Brushes.Red));
    this.Resources.Add("myTemplate", new DataTemplate());
  }
}

\n你可以将各种对象作为资源。任何你想要在整个应用程序中重复使用的东西都可以定义为资源。\n现在,当你使用\"{StaticResource}\",如下所示:\n

\n这就像告诉WPF搜索相应的\"myBrush\"资源,并将其应用于Background属性。发生的是WPF首先在按钮的资源字典中搜索资源,如果没有找到,就会搜索它的父级,然后其父级的父级,依此类推直至应用程序的资源。\n\"StaticResource\"中的\"static\"只是将其与另一种资源查找称为\"DynamicResource\"区分开。这两种之间的区别可以从此链接中了解。\n当应用于Binding时,它也是以同样的方式工作。例如,假设您在XAML中拥有以下资源:\n


\n并将其用作:\n


\n在这种情况下,发生的情况大致如下:\n

Binding b = new Binding();
b.Source = FindResource("MyPerson");
b.Path = "Name";
[TextBlock].SetBinding(TextBlock.TextProperty, b);

\n同样,在XAML中的\"{StaticResource}\"标记告诉WPF搜索相应的资源,并将其设置为属性的值,而在这种情况下,该属性是Binding的\"Source\"属性。\n这就是基础知识。希望你会发现这有帮助。

0
0 Comments

首先,一个总体的评论:

WPF 很难学。这是因为你必须同时掌握几个基本上新的概念。你现在的困难在于你正在试图同时学习至少三个不同的东西:

  • XamlReader(特别是标记扩展)如何将 XAML 反序列化为对象。
  • FrameworkElement的资源字典如何工作。
  • 数据绑定的工作原理。

像这样:


同时涉及三个非常不同的技术。这些技术都被设计成尽可能灵活,这只会让初学者更加困惑。绑定源几乎可以是任何东西的这个想法:很难理解。标记扩展是一种支持递归的特殊序列化格式:原则上很容易理解,但是当你开始处理真实世界的示例时,会有些困惑。资源字典可以包含几乎任何东西,而资源搜索算法本质上使资源可继承:同样的,概念上很简单,但在尝试同时理解数据绑定和 XAML 时很容易失去主线。

这是令人沮丧的,因为概念上简单的东西——“我想将这个控件绑定到我创建的对象的属性上”——需要你在能够在 XAML 中表达它之前理解很多事情。

唯一的解决办法是要有耐心,并确保在最低层次上理解事物。当你看到这个:

{StaticResource MyPerson}

你应该能够想到,“那将调用 StaticResource 标记扩展处理程序,在 XAML 反序列化时使用键 MyPerson 从资源字典检索对象。

一开始非常具有挑战性。我已经职业软件开发 35 年了,我发现 WPF 是迄今为止我学习的最具挑战性的技术平台。但所有这些东西都很难学习,因为它们功能强大且灵活。学习它的回报是巨大的。

稍微解决一些 karmicpuppet 没有提到的问题:

根据我在 MFC 的经验,[资源] 是图标、字符串等。

这没有改变。你仍然可以在 WPF 中创建资源文件,并在运行时将它们加载到对象中。有很多不同的方法可以做到这一点——你可以在资源编辑器中创建资源,并通过 Properties.Resources 对象加载它们,你可以将图像文件(例如)添加到项目中,将它们编译为资源,并使用它们的 URI 加载它们,还有许多其他我不知道的方法。

FrameworkElement通过它们的资源字典可以使用的资源与之前不同。不过,它们有点相似。以下是一个例子:


   


这创建了一个Image对象,并将其添加到Window的资源字典中,键为MyImage。然后可以在XAML中通过StaticResource标记扩展或者在代码中通过FindResource方法引用该对象。
在XAML中设置Image元素上的Source属性,XamlReader也会在创建Image对象时在运行时使用ResourceManager从项目的已编译资源中读取图像数据。
实际上,当你刚开始学习WPF时,这并不会像它看起来那么令人困惑。我从来没有将ResourceManager加载的资源和存储在资源字典中的资源混淆。

那么这个对象什么时候被创建呢?

任何由XAML元素定义的对象都会在XamlReader读取元素时创建。所以这样:


   


会实例化一个新的Person对象并将其添加到Window的资源字典中,键为MyPerson。这与在Window的代码后备中执行以下操作是完全等效的:

AddResource("MyPerson", new Person());


那么为什么不在后备代码中执行呢?原因有两个:
首先,这是一致的。如果您在XAML中定义所有资源,您只需要在XAML文件中查找资源。如果您在XAML和后备代码中定义它们,您必须在两个地方查找。
其次,IDE知道您在XAML中定义的资源。如果您在XAML中输入以下内容:



IDE会告诉您是否在资源字典的层次结构中未定义键为MyPerson的资源。但它不知道您在代码中添加的资源,因此即使在运行时资源实际上可能是可找到的,IDE也会将其报告为一个问题。

0