gpt4 book ai didi

c# - 在 WPF 中使用 MVVM 模式在运行时加载 XAML

转载 作者:行者123 更新时间:2023-11-30 14:15:52 26 4
gpt4 key购买 nike

这是一个从最初发布在这里延伸的问题: Link to loading-xaml through runtime

我正在开发一个 WPF MVVM 应用程序,它从外部源动态加载 XAML 内容,与上面帖子中的答案非常相似。
这是我到目前为止得到的:

  1. 我的 View 将 ViewModel 的实例声明为资源并创建该 ViewModel 的实例
  2. 在我的 ViewModel 构造函数中,我正在加载来自外部源(文件或数据库...)的 XamlString 属性
  3. 在我看来,我有一个按钮,用户在 ViewModel 完成加载后点击该按钮,在点击事件代码隐藏中,我正在反序列化动态加载的 XAML 并将其添加到我的网格中。

我的问题是,如何消除代码隐藏并使逻辑自动化,以便 View 可以在 ViewModel 获取 XAML 内容并初始化字符串属性后立即动态呈现新的 xaml 部分?

我是否应该使用某种消息传递总线,以便 ViewModel 在属性设置后发出通知,以便 View 可以添加新内容?

让我感到困扰的是,ViewModel 确实有对 View 的引用,不应该负责生成 UI 元素。

提前致谢!

编辑:澄清一下:在我的特定情况下,我并没有尝试将业务对象或集合(模型)绑定(bind)到 UI 元素(例如网格),这显然可以通过模板和绑定(bind)来完成。我的 ViewModel 正在从外部源检索整个 XAML 表单并将其设置为 View 可用的字符串属性。

我的问题是:谁应该负责将此 XAML 字符串属性反序列化为 UI元素并在设置 VM 中的 Xaml 字符串属性后以编程方式将其添加到我的网格中?
在我看来,这更像是 View 的责任,而不是 ViewModel。但据我了解,该模式强制用 V-VM 绑定(bind)替换任何代码隐藏逻辑。

最佳答案

我现在有一个可行的解决方案,我想分享它。不幸的是,我没有完全摆脱代码隐藏,但它按我预期的那样工作。这是它的工作原理(简化):

我有我的简化 ViewModel:

public class MyViewModel : ViewModelBase
{
//This property implements INPC and triggers notification on Set
public string XamlViewData {get;set;}

public ViewModel()
{
GetXamlFormData();
}

//Gets the XAML Form from an external source (e.g. Database, File System)
public void GetXamlFormData()
{
//Set the Xaml String property
XamlViewData = //Logic to get XAML string from external source
}
}

现在我的看法:

<UserControl.Resources>
<ViewModel:MyViewModel x:Key="Model"></ViewModel:MyViewModel>
</UserControl.Resources>
<Grid DataContext="{StaticResource Model}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel>
<!-- This is the Grid used as a Place Holder to populate the dynamic content!-->
<Grid x:Name="content" Grid.Row="1" Margin="2"/>
<!-- Then create a Hidden TextBlock bound to my XamlString property. Right after binding happens I will trigger an event handled in the code-behind -->
<TextBlock Name="tb_XamlString" Text="{Binding Path=XamlViewData, Mode=TwoWay, UpdateSourceTrigger=LostFocus, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Visibility="Hidden" Loaded="tb_XamlString_Loaded" />
</StackPanel>
</Grid>

基本上,我在 ViewModel 中创建了一个绑定(bind)到 XAML String 属性的隐藏 TextBlock,并将其 Loaded 事件 Hook 到 View 代码背后的事件处理程序:

    private void tb_XamlString_Loaded(object sender, RoutedEventArgs routedEventArgs)
{
//First get the ViewModel from DataContext
MyViewModel vm = content.DataContext as MyViewModel;
FrameworkElement rootObject = XamlReader.Parse(vm.XamlViewData) as FrameworkElement;
//Add the XAML portion to the Grid content to render the XAML form dynamically!
content.Children.Add(rootObject);
}

这可能不是最优雅的,但可以完成工作。正如一些人所说,在 MVVM 中,有些情况需要很少的代码隐藏代码。它没有坏处,而且在使用 VM 检索和填充 XamlString 属性并将其公开给 View 时,该解决方案的一部分仍然使用 V-VM 绑定(bind)原则。如果我们想要对 XAML 解析和加载功能进行单元测试,我们可以将其委托(delegate)给单独的类。

我希望有人觉得这有用!

关于c# - 在 WPF 中使用 MVVM 模式在运行时加载 XAML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9021677/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com