【发布时间】:2018-09-25 22:40:50
【问题描述】:
我假设这可能很容易,但我被卡住了。我有一个组合框,我可以在 viewmodel 的构造函数中更新其数据,但是如果在 viewmodel 初始化后设置数据,我将无法更新视图。我认为这要么与我的 DataContext 或我的事件广播有关,但我要么遗漏了某些东西,要么不理解某些东西。
此外,我收到与我的“DataPane”属性相关的绑定路径错误,说在 RedViewModel 中找不到它。如果我在 RedViewModel 中放置 DataPane 的属性定义,控制台将停止抱怨,但代码在这两种情况下都有效。 DataPane 是我的 MainView 的 DataContext,而不是我的 RedView,所以我不确定为什么会这样。这可能是也可能不是相关的背景信息;我最感兴趣的是这个问题的第一部分。
到目前为止,这是我的 XAML:
<UserControl x:Class="TableBuilder.Views.RedView"
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:RedViewModel />
</UserControl.DataContext>
<StackPanel Background="Red">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<TextBlock Text="Type:" Grid.Column="1" />
<TextBlock Text="Enumeration" Grid.Column="3" />
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<TextBlock Text="Value:" Grid.Column="1" />
<ComboBox Grid.Column="3" ItemsSource="{Binding EnumValueItems}" VerticalAlignment="Top">
</ComboBox>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<TextBlock Text="Units:" Grid.Column="1" />
<TextBlock Text="Integer" Grid.Column="3" />
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<TextBlock Text="Description:" Grid.Column="1" />
<TextBlock Text="text" Grid.Column="3" />
</Grid>
</StackPanel>
这是视图模型:
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Data;
using TableBuilder.Helpers;
using TableBuilder.Models;
namespace TableBuilder.ViewModels
{
public class RedViewModel : ViewModelBase
{
private object _dataPane;
public object DataPane
{
get { return _dataPane; }
private set
{
_dataPane = value;
OnPropertyChanged(nameof(DataPane));
}
}
private ListCollectionView _enumValueItems;
public ListCollectionView EnumValueItems
{
get { return _enumValueItems; }
set
{
_enumValueItems = value;
OnPropertyChanged(nameof(EnumValueItems));
}
}
public bool Loaded { get; set; }
private ObservableCollection<string> _listData;
public ObservableCollection<string> ListData
{
get { return _listData; }
set
{
_listData = value;
EnumValueItems = new ListCollectionView(ListData);
//EnumValueItems.MoveCurrentTo(ListData[0]);
//OnPropertyChanged("ListData");
}
}
public RedViewModel()
{
//_listData = new ObservableCollection<string>();
//EnumValueItems = new ListCollectionView(_listData);
//EnumValueItems.CurrentChanged += enumValueItems_CurrentChanged;
//GetListData();
}
public void GetListData()
{
ListData = new ObservableCollection<string>();
RedModel model = new RedModel();
ListData = model.GetListData();
//EnumValueItems = new ListCollectionView(model.GetListData());
//EnumValueItems.MoveCurrentTo(ListData[0]);
//EnumValueItems.CurrentChanged += EnumValueItems_CurrentChanged;
}
private void EnumValueItems_CurrentChanged(object sender, EventArgs e)
{
if (Loaded)
{
MessageBox.Show((((ListCollectionView)sender).CurrentItem).ToString());
}
Loaded = true;
}
}
}
我的 ViewModelBase 类在这里:
using System.ComponentModel;
using TableBuilder.Models;
using TableBuilder.ViewModels;
namespace TableBuilder.Helpers
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
编辑: 这是我用来尝试修改列表数据的测试代码:
public MainViewModel()
{
OpenCommand = new RelayCommand(ExecuteOpen);
ExitCommand = new RelayCommand(ExecuteExit);
var vm = new RedViewModel();
var test = new ObservableCollection<string>();
test.Add("Test1");
test.Add("Test2");
test.Add("Test3");
test.Add("Test4");
test.Add("Test5");
test.Add("Test6");
test.Add("Test7");
vm.EnumValueItems.Clear();
foreach (string s in test) { vm.EnumValueItems.Add(s); }
DataPane = vm;
}
我想我可能会以某种方式破坏这里的数据绑定。
编辑 2:
为了让问题更加清晰和清晰,这里是这个程序的总体架构(无论是好是坏):
这个程序是一个专门的 XML 解析器,用于为基于 XML 定义的嵌入式软件创建配置表。屏幕右侧根据用户选择的树节点显示 XML 数据的相关部分。左侧将显示各种视图,等待用户是否选择了 enum/float32/struct/etc 的变量。我现在感兴趣的代码是 Enum 视图,因此有一个下拉菜单,可以根据 XML 定义填充可能的枚举值。
我要做的是从 MainViewModel 填充 RedViewModel 中的下拉菜单(一旦我让一切按预期工作,这将成为我的枚举查看器)。如果我在 RedViewModel 的构造函数中填充列表,它似乎可以正确显示。但是,如果我在其他任何地方填充它(在我提供的示例中,我在实例化 RedViewModel 后将它填充到 MainViewModel 的构造函数中),它似乎不会更新。
【问题讨论】:
-
“在视图模型初始化后”设置了哪些数据,在代码中的什么位置设置?
-
我已经更新了原始帖子以包含我的测试代码。
-
您已经发布了视图模型的构造函数...?那么“在视图模型初始化之后”是什么意思?你在哪里实例化 MainViewModel 以及你在哪里绑定到 DataPane?请澄清您的问题并提供您的问题的最小示例。
-
我更新了原来的问题。简而言之,有多个视图模型。如果我在 RedViewModel 的构造函数中更新数据,它工作正常。在上面的例子中,我尝试实例化 RedViewModel 然后设置它的数据。我在另一个视图模型的构造函数中测试它,因为很容易看出它是否在那里工作。 RedView 确实显示正确,但以这种方式创建时,我的下拉菜单的内容是空的。