[英]Accessing xaml elements in viewmodel and applying dynamic styles at runtime using wpf mvvm
[英]Loading XAML at runtime using the MVVM pattern in WPF
這是一個從最初發布的問題擴展到的問題: 鏈接到loading-xaml到運行時
我正在開發一個WPF MVVM應用程序,它從外部源動態加載XAML內容,與上面帖子中的答案非常相似。
這是我到目前為止所得到的:
我的問題是,如何消除代碼隱藏和自動化邏輯,以便View可以在ViewModel完成獲取XAML內容並初始化字符串屬性后立即動態呈現新的xaml部分?
我應該使用某種消息總線,以便ViewModel在設置屬性后通知,以便View可以添加新內容嗎?
讓我感到困擾的是,ViewModel確實有對Views的引用,不應該負責生成UI元素。
提前致謝!
編輯 :只是為了澄清:在我的特定情況下,我不是試圖將業務對象或集合(模型)綁定到UI元素(例如網格),這顯然可以通過模板和綁定來完成。 我的ViewModel正在從外部源檢索整個XAML表單,並將其設置為View可用的字符串屬性。
我的問題是:誰應該負責將這個XAML字符串屬性反序列化為UI元素,並在設置VM中的Xaml字符串屬性后以編程方式將其添加到我的網格中?
這聽起來更像是一個View責任,而不是ViewModel。 但我理解的模式強制要用V-VM綁定替換任何代碼隱藏邏輯。
我現在有一個有效的解決方案,我想分享它。 不幸的是,我沒有完全擺脫代碼隱藏,但它的工作方式與我期望的一樣。 以下是它的工作原理(簡化):
我有簡化的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中創建了一個綁定到我的XAML String屬性的隱藏TextBlock,並將其Loaded事件掛鈎到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 Binding原則。 如果我們想單元測試XAML解析和加載功能,我們可以將它委托給一個單獨的類。
我希望有人覺得這很有用!
我無法理解你在說什么,所以我的答案將基於我的解釋。 您應該考慮發布您正在嘗試做的樣本(簡化)。
1)我認為你誤解了MVVM的作用。 MVVM主要是基於綁定的模式。 您的視圖模型應該公開包含業務對象的屬性,並且您的視圖應該只綁定到這些屬性。 如果我誤解了你,那就是你在做什么,那么你的問題就是你的視圖需要知道屬性何時更新(在反序列化你的xaml等之后)。 有兩種方法可以執行此操作:viewmodel上的INotifyPropertyChanged
接口,或使視圖模型繼承自DependencyObject
,並創建屬性依賴項屬性。 我不會在這里詳細介紹,因為這是一個很大的主題,您應該在做出決定之前在Google上進行研究。
2)一般來說,如果您使用的是MVVM,則不應在視圖中使用click事件。 相反,在ICommand
類型的視圖模型上創建屬性(並創建要匹配的ICommand實現,或使用DelegateCommand
(谷歌)的實現,這將允許您使用委托來實現接口。想法是,您的視圖綁定到屬性並直接在viewmodel中執行處理程序。
3)如果要將信息從視圖模型推送到視圖,那么您應該在視圖模型上創建一個事件並在視圖中訂閱它,但這是最后的手段,僅用於顯示新窗口的情況等等。一般來說,你應該使用綁定。
4)為了更具體地說明你正在做什么,你應該將Grid的ItemsSource屬性綁定到視圖模型上的某個屬性。 注意,如果您希望能夠添加項目並獲得即時更新,則視圖模型上的屬性應為ObservableCollection<T>
類型。
希望這可以幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.