有人可以解释一下这里发生了什么吗?我是WPF的新手,并通过绑定将我的Forms项目迁移到WPF。我正在使用AvalonDock,但我没有直接绑定到任何AvalonDock控件。这是一些摘录。为了简洁起见,我删除了很多,但如果你需要看别的东西,请告诉我。
编辑:这两个StackPanel只是测试...试图弄清楚这些东西。
EDIT2 :我最终试图做MVVM;我只需要更好地处理绑定,所以我知道如何构建它
EDIT3 :见帖子的底部。
问:第一个StackPanel
根本没有更新,更不用说更改后更新了。我尝试在DataContext
,StackPanel
和Grid
中设置TextBlock
。我做错了什么?
问:当父网格绑定在后面的代码中时,第二个工作正常,但只有在绑定到您看到它的位置时才能正常工作,而不是MainWindow_Loaded()
方法。这有什么不同?
我在这里阅读了几个教程以及大量类似的问题,但没有什么能帮助我理解这里的差异和我缺少的东西。
<Window x:Class="TestUIWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ad="http://schemas.xceed.com/wpf/xaml/avalondock"
Title="MainWindow" Height="768" Width="1024"
Loaded="MainWindow_Loaded"
xmlns:vm="clr-namespace:TestUIWPF.ViewModel"
>
<!-- lots excluded for brevity. there are no Window.Resources -->
<ad:LayoutAnchorable Title="Test" >
<Grid x:Name="gridTest">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<StackPanel.DataContext>
<vm:EntityViewModel />
</StackPanel.DataContext>
<TextBlock Text="Label" />
<TextBlock DataContext="{Binding ActiveEntity}" Text="{Binding Path=Label}" />
</StackPanel>
<StackPanel Orientation="Horizontal" >
<TextBlock Text="Label Again" />
<TextBlock Text="{Binding Path=Label}" />
</StackPanel>
</StackPanel>
</Grid>
</ad:LayoutAnchorable>
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = this;
SelectedEntityViewModel = new ViewModel.EntityViewModel();
ImportEntityXML_Click(null, null); //skips clicking the menus
}
private void ImportEntityXML_Click(object sender, RoutedEventArgs e)
{
//omitted OpenFileDialog and XmlReader stuff
xmlreader = new XmlReader(dlg.FileName);
Entities.Add(xmlreader.ReadEntityFromXML());
SimulatedEntitySelection(Entities.ElementAt(0)); //haven't built any of the UI stuff for this yet
}
private void SimulatedEntitySelection(Entity ent)
{
SelectedEntityViewModel.ActiveEntity = ent;
gridTest.DataContext = SelectedEntityViewModel.ActiveEntity;
}
private void button_Click(object sender, RoutedEventArgs e)
{
SelectedEntityViewModel.ActiveEntity.Label = "test";
}
Entity
和EntityViewModel
实施INotifyPropertyChanged
,它可以与第二个StackPanel
一起使用。调用button_Click()
的按钮仅用于测试绑定。 EntityViewModel
几乎只是通过Entity
属性封装ActiveEntity
,并帮助阅读Entity
中的集合集合。
EDIT3:
我也试了几个资源。这是我如何做ObjectDataProvider:
<Window.Resources>
<ObjectDataProvider x:Key="testVM" ObjectType="{x:Type vm:EntityViewModel}" />
<vm:EntityViewModel x:Key="SelEntVM" />
</Window.Resources>
<!-- .... -->
<StackPanel.DataContext>
<Binding Source="{StaticResource testVM}" />
</StackPanel.DataContext>
<TextBlock Text="Label" />
<TextBlock Text="{Binding Path=ActiveEntity.Label}" />
答案 0 :(得分:1)
确实有效。您可能可能正在更新错误的视图模型。
在DataContext
中定义视图模型后,您必须以这种方式访问它:
private void button_Click(object sender, RoutedEventArgs e)
{
var myModel = (ViewModel.EntityViewModel)(yourStackPanelName.DataContext);
myModel.ActiveEntity.Label = "test";
}
答案 1 :(得分:1)
您的第一个堆栈面板无法正常工作,因为数据上下文是继承的。因此,一旦将Grid的DataContext更改为ActiveEntity
对象,第一个数据上下文中文本块的绑定就会将TextBlock的datacontext设置为当前datacontext上的ActiveEntity
,已经是ActiveEntity
(因此ActiveEntity.ActiveEntity
)而不是尝试绑定到它上面的Label属性。例如。 ActiveEntity.ActiveEntity.Label
在点击之前,您将该窗口的DataContext设置为&#34;此&#34;我假设的不是ViewModel,它背后的代码是什么?
如果您使用的是MVVM,
你应该有这样的东西
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
SelectedEntityViewModel = new ViewModel.EntityViewModel();
this.DataContext = SelectedEntityViewModel;
ImportEntityXML_Click(null, null); //skips clicking the menus
}
或其他一些提供所有必要数据的ViewModel。
你将会有一个MainWindowView
和MainWindowViewModel
,至少这是惯例,通常你会在构造函数中设置一次窗口的datacontext(你可以在{{1}中完成在大多数情况下,您不需要手动更改后面代码中任何框架元素的DataContext。
编辑:示例代码:
MainWindow.xaml
Loaded
MainWindow.xaml.cs
<Window x:Class="SO27760357.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="300">
<Grid>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Label" />
<TextBlock Text="{Binding ActiveEntity.Label}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Label Again" />
<TextBlock Text="{Binding ActiveEntity.Label}" />
</StackPanel>
</StackPanel>
</Grid>
</Window>
MainWindowViewModel.cs(为简单起见省略了INotifyPropertChanged)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
}
EntityViewModel.cs(为简单起见省略了INotifyPropertChanged)
public class MainWindowViewModel
{
public EntityViewModel ActiveEntity { get; set; }
}
正如您所看到的,我将Window的DataContext设置为MainViewModel,因此DataContext(所有绑定的根)是MainViewModel,并且每个TextBlock需要首先访问public class EntityViewModel
{
public string Label { get; set; }
}
属性它可以进入ActiveEntity
proeprty。
另一个选择是,如果您给我们的主堆栈面板中的所有内容都绑定到ActiveEntity,您可以更改该StackPanel的DataContext,将其绑定到Label
,因此它的所有children datacontext也将是那个对象。
ActiveEntity
编辑2 - 建议
您应该尽可能避免按名称引用对象,并尽可能少地使用代码中的逻辑(如果有的话)。对于大多数简单的屏幕,除了DataContext的初始绑定之外,不需要在代码后面有任何内容(如果你没有创建+设置窗口的DataContext的窗口服务)