在 WPF/Silverlight 页面中设置自定义属性
这听起来应该很简单。我有一个 Page
以正常方式在 XAML 中声明(即使用“添加新项目...”),并且它有一个自定义属性。我想在与该页面关联的 XAML 中设置该属性。
尝试以与设置任何其他属性相同的方式执行此操作是行不通的,原因我理解但不知道如何解决。为了让我们有一些具体的东西可以讨论,这里有一些(无效的)XAML。我已经尽可能地减少了所有内容 - 最初有诸如设计师尺寸之类的属性,但我相信这些与我想要做的事情无关。
<Page x:Class="WpfSandbox.TestPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MyProperty="MyPropertyValue">
</Page>
以及相应的代码隐藏:
using System.Windows.Controls;
namespace WpfSandbox {
public partial class TestPage : Page {
public TestPage() {
InitializeComponent();
}
public string MyProperty { get; set; }
}
}
错误消息:
错误 1 XML 命名空间中不存在属性“MyProperty” 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'。第 4 行位置 7。
现在我知道为什么会失败:该元素的类型为 Page
,并且 Page
没有名为 MyProperty
的属性>。这仅在 TestPage
中声明...由 x:Class
属性指定,而不是由元素本身指定。据我所知,XAML 处理模型(即 Visual Studio 集成等)需要此配置。
我怀疑我可以使用依赖属性来处理这个问题,但这感觉有点矫枉过正。我还可以使用现有属性(例如 DataContext
),然后将值复制到代码中的自定义属性中,但这会非常难看。
上面是一个 WPF 示例,但我怀疑相同的答案也适用于 Silverlight。我对两者都感兴趣 - 因此,如果您发布一个您知道适用于其中一个但不适用于另一个的答案,如果您在答案中指出这一点,我将不胜感激:)
当有人时我正准备踢自己发布一个绝对微不足道的解决方案......
This sounds like it should be simple. I have a Page
declared in XAML in the normal way (i.e. with "Add new item...") and it has a custom property. I'd like to set that property in the XAML associated with the page.
Trying to do this the same way that I'd set any other property doesn't work, for reasons I understand but don't know how to work round. Just so we've got something concrete to talk about, here's some (invalid) XAML. I've reduced everything down as much as possible - originally there were attributes such as the designer size, but I believe those are irrelevant to what I'm trying to do.
<Page x:Class="WpfSandbox.TestPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MyProperty="MyPropertyValue">
</Page>
and the corresponding code-behind:
using System.Windows.Controls;
namespace WpfSandbox {
public partial class TestPage : Page {
public TestPage() {
InitializeComponent();
}
public string MyProperty { get; set; }
}
}
Error message:
Error 1 The property 'MyProperty' does not exist in XML namespace
'http://schemas.microsoft.com/winfx/2006/xaml/presentation'. Line 4 Position 7.
Now I know why this is failing: the element is of type Page
, and Page
doesn't have a property called MyProperty
. That's only declared in TestPage
... which is specified by the x:Class
attribute, but not by the element itself. As far as I'm aware, this configuration is required by the XAML processing model (i.e. the Visual Studio integration etc).
I suspect I could handle this with a dependency property, but that feels a little like overkill. I could also use an existing property (e.g. DataContext
) and then copy the value into the custom property in code later, but that would be pretty ugly.
The above is a WPF example, but I suspect the same answers will apply in Silverlight. I'm interested in both - so if you post an answer which you know will work in one but not the other, I'd be grateful if you'd indicate that within the answer :)
I'm preparing to kick myself when someone posts an absolutely trivial solution...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
如果您为页面创建基类,则可以使用普通属性而无需依赖属性。
即使 MyProperty 不是依赖项或附加项,它也能正常工作。
You can work with normal property without Dependency property if you create a Base class for your Page.
And it works even though MyProperty is not a Dependency or Attached.
正如 Pavel 所说,您需要将其设为可附加属性 ,那么你可以写这样的东西
但是,只有这个代码隐藏,你会得到这个错误:
编辑
不幸的是,您必须使用依赖属性。这是一个工作示例
页面
代码隐藏
如果按下按钮,您将在消息框中看到“测试...”。
You would need to make it an attachable property as Pavel noted, then you can write something like this
However, with only this code-behind, you will get this error instead:
Edit
Unfortunately, you have to use Dependency Properties. Here's a working example
Page
Code-behind
If you press the button, you will see "Testing..." in a MessageBox.
您可以将
元素声明为
元素:这可以解决问题,但您会丢失
InitializeComponent() 和标准设计器的东西。不过,设计模式似乎仍然可以完美地工作,但我还没有对此进行广泛的测试。
更新:它会编译并运行,但实际上不会设置
MyProperty
。您还失去了在 XAML 中绑定事件处理程序的能力(尽管可能有一种方法可以恢复我不知道的功能)。更新2:来自@Fredrik Mörk的工作示例,它设置属性,但不支持在XAML中绑定事件处理程序:
代码隐藏:
XAML:
You could declare your
<Page>
element to be a<TestPage>
element instead:That would do the trick, but you lose
InitializeComponent()
and the standard designer stuff. Design mode still seems to work flawlessly, though, but I haven't extensively tested this.UPDATE: This compiles and runs, but does not actually set
MyProperty
. You also lose the ability to bind event handlers in XAML (although there may be a way to restore that which I am unaware of).UPDATE 2: Working sample from @Fredrik Mörk which sets the property, but does not support binding event handlers in XAML:
Code-behind:
XAML:
您的 XAML 相当于以下内容:
这显然是非法的。 XAML 文件由 Application 类的静态 LoadComponent 方法加载,并且 参考文献说:
这意味着您只能为根元素指定的类型设置属性。因此,您需要子类化 Page 并将该子类指定为 XAML 的根元素。
Your XAML is equivalent of the following:
This is obviously illegal. The XAML-file is being loaded by the static LoadComponent method of the Application class, and the reference says:
That means that you can only set properties for the type specified by the root element. So you need to subclass Page and specify that subclass as the root element of you XAML.
这对我有用
所以这可能适用于原来的问题(没有尝试)。注意 xmlns:src。
This worked for me
So this may work for the original question (didn't try). Note xmlns:src.
答案与 Silverlight 有关。
没有简单明显的方法可以按照您想要的方式使用普通财产,在此过程中必须做出一些妥协。
实际上不起作用:-
有些人建议使用依赖属性。那是行不通的,它仍然是 Xaml POV 的公共财产。附加属性可以工作,但这会使代码中的使用变得丑陋。
关闭但没有香蕉:-
Xaml 和类可以像这样完全分离:-
代码:-
但是您会失去设计者的一些支持。值得注意的是,您必须创建字段来保存对命名元素的引用,并在您自己的
InitialiseComponent
实现中自行分配它们(IMO 所有这些命名项的自动字段无论如何都不一定是一件好事)。此外,设计器不会为您动态创建事件代码(尽管奇怪的是,它似乎知道如何导航到您手动创建的事件代码),但是 Xaml 中定义的事件将在运行时连接。IMO 最佳选择:-
最佳折衷方案已由 abhishek 发布,使用 shim 基类来保存属性。最少的努力,最大的兼容性。
Answer relates to Silverlight.
There is no simple obvious way to use plain property in the way you want, there will have to be some compromise along the way.
Doesn't really work:-
Some suggest a dependency property. That won't work, its still a public property from Xaml POV. An attached property will work but that would make working with it in code ugly.
Close but no banana:-
The Xaml and the class can be fully separated like this:-
Code:-
However you lose some support from the designer. Notably you will have to create the fields to hold references to named elements and assign them yourself in your own implementation of
InitialiseComponent
(IMO all these automatic fields for named items isn't necessarily a good thing anyway). Also the designer won't create event code dynamically for you (although strangely it seems to know how to navigate to one you have manually created) however events defined in Xaml will be wired up at runtime.IMO best option:-
The best compromise has already been posted by abhishek, use a shim base class to hold the properties. Minimul effort, maximum compatibility.
我的建议是使用默认值的
DependencyProperty
:将控件的属性视为公开给外界使用的东西。
如果您希望使用自己的属性,则可以使用
ElementName
或RelativeSource
绑定。关于过度杀戮的事情,
DependencyProperties
与DependencyObjects
齐头并进;)不需要进一步的 XAML,
PropertyMetadata
中的默认值将完成剩下的工作。如果您确实希望将其放入 XAML 中,请使用基类解决方案,否则请引入一个可附加属性,该属性也可用于任何其他控件。
My suggestion would be a
DependencyProperty
with a default:See the properties of controls as something you expose to the outside world to use.
If you wish to use your own property, you can use either
ElementName
orRelativeSource
Bindings.About the overkill thing,
DependencyProperties
go hand in hand withDependencyObjects
;)No further XAML needed, the default in the
PropertyMetadata
will do the rest.If you really wish to put it in the XAML, go for the base class solution, or gods forbid, introduce an attachable property, which can be used on any other control as well.
不过,我只是尝试以不同的意图做同样的事情。
真正的答案实际上是:您需要正确完成 Set 方法的 WPF 约定。
如此处所述: http://msdn.microsoft.com/en-us /library/ms749011.aspx#custom
如果要定义名为 Xxx 的附加属性,则必须定义 SetXxx 和 GetXxx 方法。
所以请参阅这个工作示例:
以及 WPF 部分:
顺便说一句:您还需要继承 DependencyObject
I just tried to do the same with some different intent, though.
The real answer actually is: You need the WPF convention for Set-methods done right.
As outlined here: http://msdn.microsoft.com/en-us/library/ms749011.aspx#custom
you have to define the SetXxx and GetXxx methods if you are about to definde an attached property named Xxx.
So see this working example:
And the WPF part:
BTW: You need also to inherit DependencyObject
您需要将其定义为可附加属性才能像这样访问它。
You would need to define it is attachable property to access it like this.
您可以使用样式设置属性:
但它仅适用于依赖属性!
You can set the property with a style:
But it only works for dependency properties!