在进行了一段时间的Silverlight开发之后,我目前正在进行一些WPF工作...
我经常使用这个技巧来使我的一些ValueConverters更加方便:
public class MyCovnerterWithDataContext : FrameworkElement, IValueConverter
{
private MyDataContextType Data
{
get { return this.DataContext as MyDataContextType; }
}
....
现在我可以在转换器方法中访问我的DataContext,这对于许多情况非常方便,您可以想象得到。
我尝试在WPF中使用同样的技巧,但不幸的是这根本不起作用。 调试输出中会出现以下错误:
“找不到提供DataContext的元素”
我认为资源在Silverlight中是视觉树的一部分,而在WPF中则不是。
那么 - 我的小技巧在WPF中是否可行? 我的小技巧是否应被视为肮脏的黑客技术?
您有什么看法和建议?
问候 约翰内斯
更新: 根据要求,以下是更多信息 - 实际上是一个最小化的示例:
XAML:
<Window x:Class="WpfDataContextInResources.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfDataContextInResources"
x:Name="window"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:TestWrapper x:Key="TestObj" />
</Window.Resources>
<StackPanel>
<TextBlock Text="{Binding Text}" />
<TextBlock Text="{Binding DataContext.Text, Source={StaticResource TestObj}, FallbackValue='FALLBACK'}" />
</StackPanel>
</Window>
这是一个 .cs 文件:
namespace WpfDataContextInResources
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new DataClass()
{
Text = "Hello",
};
}
}
public class TestWrapper : FrameworkElement {}
public class DataClass
{
public string Text { get; set; }
}
}
至少在我的电脑上,下方的文本块保持了回退值。
更新 #2:
我尝试了Martin提出的建议(派生自DependencyObject、创建自己的DependencyProperty等),但它也没有起作用。不过这次错误信息是另一种:
"System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:(no path); DataItem=null; target element is 'TestWrapper' (HashCode=28415924); target property is 'TheData' (type 'Object')"
我也有一些解决方法的建议:
1.) - 使用MultiBinding --> 与Silverlight不兼容,在某些情况下不足够。
2.) - 使用另一个包装对象,在代码后台手动设置DataContext,像这样 --> 与Silverlight完全兼容(除了不能直接使用Framework-Element之外 - 必须制作一个继承自它的空类)
xaml:
<Window.Resources>
<FrameworkElement x:Key="DataContextWrapper" />
<local:TestWrapper x:Key="TestObj" DataContext="{Binding DataContext, Source={StaticResource DataContextWrapper}}" />
...
后端代码:
//of course register this handler!
void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var dcw = this.Resources["DataContextWrapper"] as FrameworkElement;
dcw.DataContext = this.DataContext;
}