我正在尝试学习WPF,但我发现很难理解绑定,"资源"事物和对象创建.我的背景是C++/MFC和C#-Winforms.
我的问题:
我在XAML中看到的大多数示例(在MSDN和我读过的其他两本WPF书籍中)都在绑定表达式中使用StaticResource.这些是否与静态成员有关?或者这只是一个误导性的名字?当作为StaticResource对任何对象进行引用时,它何时被实例化?
据我所知,StaticResources与app/window/control等"Resources"部分中定义的"things"一起使用.
现在,这些参考资料部分对我来说非常混乱.究竟是什么?根据我在MFC中的经验,这些是图标,字符串等.但是,从我看到的所有示例来看,在WPF中,这些似乎基本上是(a)标记中的各种全局对象定义的"倾销场"
(样式,数据模板等)
(b)标记中的各种全局对象实例化我是否正确?这让我非常凌乱.
它主要涉及在XAML中学习各种半DSL(用于定义样式,定义数据模板,创建对象等),并将它们粘贴在同一个地方.我一直在想像手工编辑MFC中的资源文件(.rc).至少那些部分是完全分开的,每个资源的语法都相对简单.
要理解前面两个问题:当我在参考资料部分定义一个对象实例,然后从StaticResource绑定中引用它时,它究竟何时被实例化?MSDN说(在"如何:使数据可用于XAML中绑定"中):
您可以使对象可用于绑定的一种方法是将其定义为资源
但是,这不是很清楚.他们的意思是什么?他们的意思是创造?它们是否意味着连接到绑定子系统?什么时候创建该对象?从一个简单的例子开始,我看到WPF似乎在尝试附加绑定时为我创建了这个对象.这更令人困惑.
编辑:在下面的karmicpuppet澄清后,我仍然对如何连接到Binding感到困惑.假设我有我的资源:
<local:Person x:Key="MyPerson" Name="Title"/>
Run Code Online (Sandbox Code Playgroud)
(其中Person是一个名为Name的属性的类)然后在窗口中我有:
<TextBlock Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/>
Run Code Online (Sandbox Code Playgroud)
1)这是做什么的?它是否经历了相同的步骤 - 搜索资源然后将其应用于Text属性?MyPerson对象是在创建Window时创建的,还是稍后创建的?2)我是否必须使用绑定机制绑定到Name属性?我不能像你上面用myBrush那样直接绑定它吗?为什么我不能这样做?
<TextBlock Text="{StaticResource MyPerson, Path=Name}"/>
Run Code Online (Sandbox Code Playgroud)
这只是框架方面的短视吗?我想我在这里失踪很多,但我似乎无法明白...
3)我尝试使用DynamicResource,但我对我采取的每一步都非常困惑.a)在我的单个Window类的代码中添加了一个带有DependencyProperty的DependencyObject(这个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));
}
Run Code Online (Sandbox Code Playgroud)
b)在Windows.Resources中添加了一个实例(这对于DynamicResource是必要的吗?MSDN似乎说没有,但是如果是这样的话,我无法弄清楚如何在XAML中进行下一步)
c)我试过两个:
Text="{Binding Source={DynamicResource HeaderText}, Path=Header}"
Run Code Online (Sandbox Code Playgroud)
这给了我一个例外,并且
Text="{DynamicResource HeaderText}"
Run Code Online (Sandbox Code Playgroud)
但我无法理解将路径放到Header属性的位置.
这是我最近第五次尝试使用WPF,每次我都被这些看似简单的事情所困扰.我已经阅读了2本书,我真的试图理解MSDN的文章,但它们根本没有帮助.
Rob*_*ney 38
首先,整体评论:
WPF很难学.这很难学,因为有几个不同的基本新概念,你必须同时了解.你现在正在进行的斗争是,你试图同时学习至少三种不同的东西:
XamlReader(特别标记扩展)XAML反序列化到对象.FrameworkElement资源词典是如何工作的.像这样的东西:
<TextBox Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/>
Run Code Online (Sandbox Code Playgroud)
同时参与(至少)三种截然不同的技术.这些技术都设计得尽可能灵活,这只会让初学者更加困惑.绑定源几乎可以是任何东西的想法:很难掌握.标记扩展是一种支持递归的特殊序列化格式的想法:原理简单到理解,但是当你第一次开始使用真实世界的例子时,有点令人费解.资源字典几乎可以包含任何内容的想法,以及资源搜索算法本质上使资源可以继承:再次,在概念上非常简单,但当你试图找出数据绑定和XAML时容易丢失线程同一时间.
令人沮丧的是,因为概念上简单的东西 - "我想将这个控件绑定到我创建的对象的属性" - 要求你在XAML中实际表达它之前理解很多东西.
唯一的解决方案是耐心等待,并确保您尽可能地了解最低级别的事物.当你看到这个:
{StaticResource MyPerson}
Run Code Online (Sandbox Code Playgroud)
您应该能够思考,"这将调用StaticResource标记扩展处理程序,该处理程序MyPerson在反序列化XAML时使用密钥从资源字典中检索对象.
一开始这是非常具有挑战性的.我已经专业开发了35年的软件,我发现WPF是我所学到的最具挑战性的技术平台.但所有这些东西都难以学习,因为它具有令人难以置信的功能和灵活性.学习它的回报是巨大的.
要解决karmicpuppet没有解决的几个问题:
根据我在MFC中的经验[资源]是图标,字符串等.
这没有改变.您仍然可以在WPF中创建资源文件,并在运行时将它们加载到对象中.有很多不同的方法可以做到这一点 - 您可以在资源编辑器中创建资源并通过Properties.Resources对象加载它们,您可以将图像文件(例如)添加到项目中,将它们编译为资源,并使用它们加载它们,还有很多其他方法,我不知道.
FrameworkElement通过资源字典可用的资源是另一回事.好吧,有点.这是一个例子:
<Window.Resources>
<Image x:Key="MyImage" Source="images/myimage.png"/>
</Window.Resources>
Run Code Online (Sandbox Code Playgroud)
这将创建一个Image对象,并使用键将其添加到Window资源字典中.MyImage 然后,您可以通过StaticResourceXAML中的标记扩展或FindResource代码中的方法引用该对象.
在XAML中设置元素的Source属性还可以使用它在创建对象时在运行时从项目的已编译资源中读取图像数据.ImageXamlReaderResourceManagerImage
实际上,这远不像你第一次学习WPF那样令人困惑.我从来没有得到资源ResourceManager加载和资源字典中存储的资源混淆.
什么时候创建该对象?
XamlReader读取元素时会创建由XAML元素定义的任何对象.所以这:
<Window.Resources>
<local:Person x:Key="MyPerson"/>
</Window.Resources>
Run Code Online (Sandbox Code Playgroud)
实例化一个新Person对象,并Window用一个键将其添加到资源字典中MyPerson.它完全等同于在Window代码隐藏中执行此操作:
AddResource("MyPerson", new Person());
Run Code Online (Sandbox Code Playgroud)
那你为什么不在代码隐藏中做呢?两个原因:
首先,它是一致的.如果在XAML中定义所有资源,则只需查看XAML文件即可查找资源.如果在XAML和代码隐藏中定义它们,则必须查看两个位置.
其次,IDE了解您在XAML中定义的资源.如果你输入
<TextBox Text="{Binding {StaticResource MyPerson}, Path=Name}"/>
Run Code Online (Sandbox Code Playgroud)
在您的XAML中,如果您没有在资源字典的层次结构中的某个位置定义密钥为的资源,IDE将通知您MyPerson.但它不知道您在代码中添加的资源,因此即使资源实际上可以在运行时找到,IDE也会将其报告为问题.
ASa*_*nch 14
可以这样考虑:所有FrameworkElements(Windows,按钮,其他控件等)以及Application对象都包含一个Dictionary of Resources.每当您在XAML中定义资源时,如下所示:
<Window>
<Window.Resources>
<SolidColorBrush x:Key="myBrush" Color="Red"/>
<DataTemplate x:Key"myTemplate">
<!--Template definition here -->
</DataTemplate>
</Window.Resources>
</Window>
Run Code Online (Sandbox Code Playgroud)
这就像在代码中做这样的事情:
class Window
{
void Window()
{
this.Resources.Add("myBrush", new SolidColorBrush(Brushes.Red));
this.Resources.Add("myTemplate", new DataTemplate());
}
}
Run Code Online (Sandbox Code Playgroud)
您可以将各种对象作为资源.您希望在整个应用程序中重复使用的任何内容,都可以将其定义为资源.
现在,当您使用"{StaticResource}"时,如下所示:
<Button Background="{StaticResource myBrush}"/>
Run Code Online (Sandbox Code Playgroud)
这就像告诉WPF搜索相应的"myBrush"资源并将其应用于Background属性.会发生什么是WPF将首先在Button的资源字典中搜索资源,如果找不到它将搜索其父级,然后搜索其父级的父级,依此类推,直至应用程序的资源.
"StaticResource"中的"静态"事物只是将其与名为"DynamicResource"的其他类型的资源查找区分开来.在这个链接中回答了两者之间的差异.
当应用于Binding时,它也以相同的方式工作.例如,假设您的XAML中包含以下资源:
<local:Person x:Key="MyPerson" Name="Title"/>
Run Code Online (Sandbox Code Playgroud)
并用它作为:
<TextBlock Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/>
Run Code Online (Sandbox Code Playgroud)
在这种情况下,会发生的事情是这样的:
Binding b = new Binding();
b.Source = FindResource("MyPerson");
b.Path = "Name";
[TextBlock].SetBinding(TextBlock.TextProperty, b);
Run Code Online (Sandbox Code Playgroud)
同样,XAML中的"{StaticResource}"标记告诉WPF搜索相应的资源并将其设置为a属性的值.在这种情况下,属性是Binding的"Source"属性.
这是基础知识.希望你觉得这很有帮助