【发布时间】: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 在未初始化的情况下能够正常工作,那就太奇怪了。