3

我正在尝试在运行时对代码中Run的 a进行数据绑定TextBlock,但我终生无法弄清楚如何。

Internet 上的一些消息来源表明,如果没有一些(不太漂亮)额外的解决方法,这是不可能的,更重要的是,当您尝试在 XAML 中执行此操作时,它应该完全失败。

然而,在我的应用程序中,我有以下内容,效果很好:

<DataTemplate x:Key="PitchTemplate">
    <Grid Width="120" Height="120" HorizontalAlignment="Center" VerticalAlignment="Center">
        <TextBlock HorizontalAlignment="Center"
                   VerticalAlignment="Center"
                   TextAlignment="Center">
            <Run Text="{Binding}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" FontSize="36"/>
            <LineBreak/>
            <Run Text="{Binding Frequency, StringFormat=\{0:n2\}Hz}" FontFamily="{StaticResource PhoneFontFamilyNormal}" Foreground="{StaticResource PhoneSubtleBrush}"/>
        </TextBlock>
    </Grid>
</DataTemplate>

所以我想:如果可以在 XAML 中完成,那么应该可以在代码中完成。

到目前为止,无济于事。在代码中使用“常规”绑定方式是行不通的;该类Run不继承自FrameworkElement,因此没有SetBinding方法,并且它的Text属性不是DependencyProperty.

使用BindingOperations.SetBinding不起作用,因为该Text属性不是DependencyProperty.

我已经到了我愿意接受它不能在运行时完成的点上(尽管不是没有最后一次尝试 StackOverflow),但我仍然很好奇是否

  • 这可以在运行时在代码中完成吗?

如果不:

  • 它如何在 XAML 中工作?

编辑:

显示的示例只是为了表明它可以在 XAML 中完成。我需要在代码中创建绑定的原因是我有一个控件可以动态创建其他元素,这些元素需要进行数据绑定。

更新:

As Pete and I both found out, there is a dependency property for Text, but it's private. I assume that's why it does work through XAML (the xaml parser probably has more rights when it comes to reflection, and more knowledge in general about classes).

The upside is, that this means (tried & tested) it also works through XamlReader.Load(), which is (sofar) the cleanest solution I've come up with.

But if anyone has anything better, I'd be glad to hear about it.

4

3 回答 3

2

Run.Text is backed by the private TextProperty which means you can't directly set its value without some reflection gimmicks, something like this:

        Run r=new Run();
        r.Text = "Moo";
        var field=r.GetType().GetField("TextProperty", BindingFlags.Static | BindingFlags.NonPublic);
        var dp=field.GetValue(null) as DependencyProperty;
        BindingOperations.SetBinding(r, dp, new Binding {...});

This is rather ugly, but perhaps it can be useful.

You can find various workarounds for this. This SO post uses a custom attached property to configure binding. The attached property is used because Run is a sealed class in Silverlight so you can't create you own Run that supports binding.

于 2012-06-08T08:46:23.347 回答
1

The reason that it works in XAML but not in code-behind might be that there is a dependency property for Text, but it is private. It's a little bit 'black magic' to me though, so that's just a guess! This is a strange one, as in WPF the Run does inherit from FrameworkContentElement and has a SetBinding method...

Could you create a subclass of Run that contains a public DependencyProperty for text? I'm afraid I don't have the Silverlight dev tools to hand to try it out at the moment, but I'll try and take a look later.

于 2012-06-08T08:40:17.260 回答
0

Thanks both to Pete & Panagiotis for their efforts and suggestions (both 1 up).

In the end, I decided to go with my own solution (found in the "Update" section of the question): Create dedicated XAML strings containing the Run including the binding, and use XamlReader.Load() to parse it, and return a Run object.

The situation I'm working on is quite specific, so a local solution to the problem is good enough (for now). Reflection, as suggested by Panagiotis, won't work due to restrictions imposed by Silverlight. Lastly, the BindableRuns solutions would need either extensive work to deal with nested properties, or I would have to "uglify" my view model, so I discarded it (also for now).

Thanks all for your input.

于 2012-06-08T09:38:08.793 回答