[英]WPF MVVM TreeView using HierarchicalDataTemplate not updating
[英]WPF Treeview Not Updating After Rearchitecting to MVVM
我創建了一個應用程序,用於加載格式特殊的XML文件並通過WPF GUI編輯其字段。 但是,由於是C#的新手,所以我在編寫MVVM模式時並不了解它,因此我采取了快速而又骯臟的方法,即僅對后面的代碼進行編碼。 但是,在重新構建后,我似乎無法再更新樹狀視圖(以前正在工作的)。
這是相關的XAML:
<UserControl x:Class="TableBuilder.Views.XmlView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:views="clr-namespace:TableBuilder.Views"
xmlns:viewmodels="clr-namespace:TableBuilder.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.DataContext>
<viewmodels:XmlViewModel />
</UserControl.DataContext>
<DockPanel>
<TreeView x:Name="XmlTree" SelectedItemChanged="XmlView_SelectedItemChanged">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="20" Margin="2" Source="../Images/Red_Bullet.png" />
<TextBlock VerticalAlignment="Center" Text="{Binding}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
</TreeView>
</DockPanel>
</UserControl>
下面是代碼:
using System;
using System.Windows;
using System.Windows.Controls;
using TableBuilder.Helpers;
namespace TableBuilder.Views
{
/// <summary>
/// Interaction logic for XmlView.xaml
/// </summary>
public partial class XmlView : UserControl
{
RelayCommand selectedItemChanged { get; set; }
public XmlView()
{
InitializeComponent();
}
private void XmlView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
//((MainViewModel)this.DataContext).SelectedItemChangedCommand = (RelayCommand)sender;
Console.WriteLine("XmlView selected item changed event triggered");
}
}
}
這是視圖模型:
using System;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Xml;
using TableBuilder.Helpers;
using TableBuilder.Models;
namespace TableBuilder.ViewModels
{
class XmlViewModel : ViewModelBase
{
private TreeView _xmlTree;
public TreeView XmlTree
{
get { return _xmlTree; }
set
{
_xmlTree = value;
OnPropertyChanged("XmlTree");
}
}
public XmlViewModel()
{
xmlModel = new XmlModel();
TreeView XmlTree = new TreeView();
TreeViewItem node = new TreeViewItem();
node.Header = "Test";
XmlTree.Items.Add(node);
xmlModel.PropertyChanged += XmlModel_CurrentChanged;
}
private void XmlModel_CurrentChanged(object sender, EventArgs e)
{
TreeViewItem xmlTreeItems = GetTreeViewItems();
TreeView XmlTree = new TreeView();
XmlTree.Items.Add(xmlTreeItems);
}
private TreeViewItem GetTreeViewItems()
{
// Find the filename of the XML document
Uri uri = new Uri(xmlModel.XmlDoc.BaseURI);
string filename = "";
if (uri.IsFile)
{
filename = System.IO.Path.GetFileName(uri.LocalPath);
}
// Populate the TreeView
TreeViewItem TitleNode = new TreeViewItem()
{
Header = filename,
Tag = "Title Node",
};
PopulateTree(TitleNode, xmlModel.XmlDoc.ChildNodes);
return TitleNode;
}
private void PopulateTree(TreeViewItem parent, XmlNodeList nodes)
{
TreeViewItem item;
Dictionary<string, string> dict;
bool isSmallestChild;
foreach (XmlNode node in nodes)
{
// Ignore all comments in the XML document
if (!node.Name.Contains("#comment"))
{
// Add to TreeView
item = toTreeViewItem(node);
isSmallestChild = false;
dict = new Dictionary<string, string>();
foreach (XmlNode child in node.ChildNodes)
{
if (child.Name.Contains("type") ||
child.Name.Contains("value") ||
child.Name.Contains("units"))
{
isSmallestChild = true;
}
if (isSmallestChild)
{
dict.Add(child.Name, child.InnerText);
}
}
if (!isSmallestChild)
{
PopulateTree(item, node.ChildNodes);
}
else
{
item.Tag = dict;
}
parent.Items.Add(item);
}
}
}
private TreeViewItem toTreeViewItem(XmlNode node)
{
TreeViewItem item = new TreeViewItem()
{
Header = node.Name.Contains("#") ? node.InnerText : node.Name,
};
return item;
}
}
}
這是模型:
using System.Xml;
using TableBuilder.Helpers;
namespace TableBuilder.Models
{
public class XmlModel : ModelBase
{
private XmlDocument _xmlDoc;
public XmlDocument XmlDoc
{
get { return _xmlDoc; }
set
{
_xmlDoc = value;
OnPropertyChanged("XmlDoc");
}
}
public XmlModel()
{
XmlDoc = new XmlDocument();
}
}
}
這是viewmodel基類:
using System.ComponentModel;
using TableBuilder.Models;
namespace TableBuilder.Helpers
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
static protected RedModel redModel { get; set; }
static protected XmlModel xmlModel { get; set; }
static protected MainModel mainModel { get; set; }
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
最后,這是模型基類:
using System.ComponentModel;
namespace TableBuilder.Helpers
{
public class ModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
我知道代碼中有很多草率的做法。 這是我的第一個C#/ WPF應用程序。 為了幫助限制此問題的范圍,我只想知道為什么不能從我的視圖模型設置樹視圖數據。 我曾嘗試在Google周圍閑逛,但沒有成功。 我應該注意,我能夠用文本框替換樹視圖,並從視圖模型中將數據設置為文本框,而不會出現問題。
有關解決方案,請參見上面的注釋部分。 elgonzo指出了在重新架構過程中發生的主要架構問題:視圖模型不直接與UI元素交互,它們與XAML中綁定到UI元素的數據交互。
另一個遺漏的部分是由於我在主視圖模型中再次實例化了視圖模型以創建適當的外觀,但是,這破壞了子窗口的數據上下文,這意味着我只能在構造函數中操作數據。 解決方案是在更改UI方面而不是視圖模型時實例化VIEWS。 這樣做可以保留數據上下文。
編輯:我的XmlPane沒有發送正在更新的通知。 實例化視圖模型上的視圖是這樣做的結果,而不是我上面提到的結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.