绑定为资源
Binding as a Resource
我可以将 Binding
定义为 Resource
,然后使用不同的 Controls
属性重用它吗?
示例:
绑定:
<Window.Resources>
<Binding x:Key="MyBinding" Path="MyProperty" Mode="TwoWay" />
</Window.Resources>
在XAML中重用:
<TextBox Text="{StaticResource MyBinding}" />
如上声明 Binding
后出现错误:
"The name 'InitializeComponent' does not exist in the current
context"
有什么方法可以在不同的上下文中重复使用相同的 Binding
吗?
这里有两种方法可以不完全按照您的意愿行事:
1.使用自定义标记扩展
为了简短起见,跳过了所有 nullchecks 等。
using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
public class BindingDefinition
{
public PropertyPath Path { get; set; }
public BindingMode Mode { get; set; }
}
[MarkupExtensionReturnType(typeof(BindingExpression))]
public class ApplyBindingDefinition : MarkupExtension
{
public BindingDefinition Definition { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = new Binding
{
Path = this.Definition.Path,
Mode = this.Definition.Mode
};
return binding.ProvideValue(serviceProvider);
}
}
<Window.Resources>
<local:BindingDefinition x:Key="MyProperty"
Mode="TwoWay"
Path="MyProperty" />
</Window.Resources>
<TextBox>
<TextBox.Text>
<!-- using element style here as the parser chokes on parsing nested markupextensions -->
<local:ApplyBindingDefinition Definition="{StaticResource MyProperty}" />
</TextBox.Text>
</TextBox>
2。使 PropertyPath 成为资源
可能无法满足您的需求。
<Window.Resources>
<PropertyPath x:Key="MyPropertyPath">MyProperty</PropertyPath>
</Window.Resources>
...
<TextBox Text="{Binding Path={StaticResource MyPropertyPath}}" />
您问题的直接答案是 "yes, you can define a binding as a resource"。这里的问题是您如何使用它?一种可能性是创建一个扩展 class,它将从资源中提取绑定并应用它:
public class BindingResourceExtension : StaticResourceExtension
{
public BindingResourceExtension() : base() { }
public BindingResourceExtension(object resourceKey) : base(resourceKey) { }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = base.ProvideValue(serviceProvider) as BindingBase;
if (binding != null)
return binding.ProvideValue(serviceProvider);
else
return null; //or throw an exception
}
}
用法示例:
<Window.Resources>
<ResourceDictionary>
<Binding x:Key="MyBinding" Path="MyProperty" Mode="TwoWay" />
</ResourceDictionary>
</Window.Resources>
(...)
<TextBox Text="{ns:BindingResource MyBinding}" />
这个解决方案可以用在 MultiBinding
吗?
是的,它可以:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="First: {0}, Second: {1}">
<Binding Path="SomeProperty" />
<ns:BindingResource ResourceKey="MyBinding" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
然而,这有一个缺点 - 虽然一切都会在 运行 时间内运行,但 XAML 设计师 会抱怨 BindingResourceExtension
的类型不适合放入 MultiBinding.Bindings
集合。但是,值得庆幸的是,有一个快速的解决方案 - 只需使用 StaticResourceExtension
即可!因此,虽然在 运行 时间内在功能上是等效的,但将被设计者接受:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="First: {0}, Second: {1}">
<Binding Path="SomeProperty" />
<StaticResource ResourceKey="MyBinding" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
我可以将 Binding
定义为 Resource
,然后使用不同的 Controls
属性重用它吗?
示例:
绑定:
<Window.Resources>
<Binding x:Key="MyBinding" Path="MyProperty" Mode="TwoWay" />
</Window.Resources>
在XAML中重用:
<TextBox Text="{StaticResource MyBinding}" />
如上声明 Binding
后出现错误:
"The name 'InitializeComponent' does not exist in the current context"
有什么方法可以在不同的上下文中重复使用相同的 Binding
吗?
这里有两种方法可以不完全按照您的意愿行事:
1.使用自定义标记扩展
为了简短起见,跳过了所有 nullchecks 等。
using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
public class BindingDefinition
{
public PropertyPath Path { get; set; }
public BindingMode Mode { get; set; }
}
[MarkupExtensionReturnType(typeof(BindingExpression))]
public class ApplyBindingDefinition : MarkupExtension
{
public BindingDefinition Definition { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = new Binding
{
Path = this.Definition.Path,
Mode = this.Definition.Mode
};
return binding.ProvideValue(serviceProvider);
}
}
<Window.Resources>
<local:BindingDefinition x:Key="MyProperty"
Mode="TwoWay"
Path="MyProperty" />
</Window.Resources>
<TextBox>
<TextBox.Text>
<!-- using element style here as the parser chokes on parsing nested markupextensions -->
<local:ApplyBindingDefinition Definition="{StaticResource MyProperty}" />
</TextBox.Text>
</TextBox>
2。使 PropertyPath 成为资源
可能无法满足您的需求。
<Window.Resources>
<PropertyPath x:Key="MyPropertyPath">MyProperty</PropertyPath>
</Window.Resources>
...
<TextBox Text="{Binding Path={StaticResource MyPropertyPath}}" />
您问题的直接答案是 "yes, you can define a binding as a resource"。这里的问题是您如何使用它?一种可能性是创建一个扩展 class,它将从资源中提取绑定并应用它:
public class BindingResourceExtension : StaticResourceExtension
{
public BindingResourceExtension() : base() { }
public BindingResourceExtension(object resourceKey) : base(resourceKey) { }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = base.ProvideValue(serviceProvider) as BindingBase;
if (binding != null)
return binding.ProvideValue(serviceProvider);
else
return null; //or throw an exception
}
}
用法示例:
<Window.Resources>
<ResourceDictionary>
<Binding x:Key="MyBinding" Path="MyProperty" Mode="TwoWay" />
</ResourceDictionary>
</Window.Resources>
(...)
<TextBox Text="{ns:BindingResource MyBinding}" />
这个解决方案可以用在 MultiBinding
吗?
是的,它可以:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="First: {0}, Second: {1}">
<Binding Path="SomeProperty" />
<ns:BindingResource ResourceKey="MyBinding" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
然而,这有一个缺点 - 虽然一切都会在 运行 时间内运行,但 XAML 设计师 会抱怨 BindingResourceExtension
的类型不适合放入 MultiBinding.Bindings
集合。但是,值得庆幸的是,有一个快速的解决方案 - 只需使用 StaticResourceExtension
即可!因此,虽然在 运行 时间内在功能上是等效的,但将被设计者接受:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="First: {0}, Second: {1}">
<Binding Path="SomeProperty" />
<StaticResource ResourceKey="MyBinding" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>