【问题标题】:(Yet another) attached property binding not working(又一个)附加属性绑定不起作用
【发布时间】:2020-05-15 07:41:09
【问题描述】:

一开始我尝试制作 UWP 应用程序,但后来意识到它对我来说限制太多,现在尝试将现有代码移植到经典 WPF。我正在使用 .NET Core 3.1、Caliburn、Kinnara/ModernWpf、Microsoft.NETCore.Windows.ApiSets、Microsoft.Windows.SDK.Contracts 和 System.Windows.Interactivity.WPF(尽管实际上并没有使用最后一个)。 所以,基本上,它应该为我提供了相当流畅的 WPF 移植,但正如我发现的那样,Caliburn 的附加属性 View.Model 不起作用。我尝试创建自己的附加属性并将其绑定到 VM 的测试属性,但它也没有工作,该属性永远不会被访问并且附加属性的值为 null。

基本代码如下:

(这不是真实的情况,在实际情况下我在 NavigationView.ContentTemplate 中使用 ContentPresenter,但这种情况在实践中应该是相同的。并且我已经在外部使用 ContentPresenter 进行了测试,并且将 NavigationView 注释掉了。另外,例如,如果我使用 TextBlock 而不是 ContentPresenter,则绑定可以正常工作,并且附加属性的值符合预期。可能有什么问题以及 ContentPresenter 的不同之处是什么?)

视图模型

    public class ShellViewModel : Conductor<IScreen>.Collection.OneActive
    {
        public ShellViewModel()
        {
            ActiveItem = new SomeOtherViewModelDerivedFromScreen();
            Task.Delay(3000).ContinueWith(task => OnPropertyChanged(new PropertyChangedEventArgs("HelloWorld")));
            // This is getting called ok, though AFAIK it's not even necessary to raise PropertyChanged
        }
    ...

        public string HelloWorld => "Hello world"; // Breakpoint here, never gets called
    ...
    }

附加属性

    public static class Test
    {
        public static readonly DependencyProperty TestProperty = 
            DependencyProperty.RegisterAttached("Test", typeof(object), typeof(Test), 
                new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, 
                TestChangedCallback));

        public static object GetTest(UIElement element)
        {
            // Breakpoint here, never gets called
            return element.GetValue(TestProperty);
        }

        public static void SetTest(UIElement element, object value)
        {
            // Breakpoint here, never gets called
            element.SetValue(TestProperty, value);
        }
        private static void TestChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // Breakpoint here, never gets called
        }
    }

XAML

<Window x:Class="RecipeCalculator.Views.ShellView"
        ... >
    <Grid>
        <ContentPresenter x:Name="TestCP" t:Test.Test="{Binding Path=HelloWorld}" Content="{Binding ActiveItem}"/>
    </Grid>
</Window>

背后的代码

public partial class ShellView : Window
    {
        public ShellView()
        {
            InitializeComponent();
            this.Loaded += OnLoaded;
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            var val = TestCP.GetValue(ViewModels.Test.TestProperty);
            // Breakpoint here, val is null.
        }
    }

【问题讨论】:

  • 我发现的第一件事是我应该使用 ContentControl 而不是 ContentPresenter。我不明白它们之间有什么区别......不过,如果我在 NavigationView.ContentTemplate 中使用 ContentControl,附加的属性绑定不起作用。但是如果在这个例子中使用 ContentControl,在外面,一切正常,属性被设置,视图被找到。
  • 很多人都喜欢 Caliburn Micro,但根据我的经验,它的“魔力”只会让开发在某些事情不工作时变得悲惨。我强烈建议放弃它并使用更传统的 MVVM 方法。
  • @Keithernet 我刚刚尝试了“更传统的 MVVM 方法”,那是另一种悲惨的体验,因为 WPF 是纯粹的魔法。黑的那个。我已经下载并引用了 Caliburn 源,所以至少在那里我可以追踪比我在 XAML 方面更有经验的人是如何完成工作的。但是,当我什至无法让一些更简单的案例正常工作时,它仍然没有用。
  • 呃,而且看起来 Caliburn 也与它无关,因为正如我已经说过的,它的所有附加属性都因某种原因不起作用。如果 caliburn 在未初始化的情况下能够正常工作,那就太奇怪了。

标签: c# .net wpf xaml


【解决方案1】:

您应该将ContentPresenter 替换为ContentControl

<ContentControl x:Name="TestCP" t:Test.Test="{Binding Path=HelloWorld}" 
                Content="{Binding ActiveItem}"/>

ContentPresenter 仅用于在ControlTemplate 中显示ContentControlContent。它不继承 DataContext,这就是您的绑定不起作用的原因。

【讨论】:

  • 我刚刚发现它,实际上是在一分钟前。我目前正在发布我的答案。
  • 为什么要发布我的答案副本而不是接受它?再合适不过了。
  • 因为它不是您答案的副本。实际上,对于我的情况,您的答案并不完整,因为正如我在问题中所说,主要问题是 NavigationView 中的 AttachedProperty,即使我将 ContentPresenter 替换为 ContentControl 也无法解决,因为我也将绑定添加到 ContentTemplate。但如果你愿意,好吧,我会接受你的回答,无论如何。
【解决方案2】:

经过大量测试、试验和谷歌搜索,我已经弄清楚了。

Kinnara/ModernWpf 正在使用 ContentPresenter,它会丢弃 DataContext as stated in this article。此外,它的 ContentPresenter/ContentControl 没有在模板中绑定到 ContentTemplate、ContentTemplateSelector 和 ContentStringFormat,因此我设置的 ContentTemplate 从未实际使用过,因为它没有被控件绑定。修复源代码后,一切正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 2017-07-02
    • 2011-02-07
    相关资源
    最近更新 更多