有人可以解释一下这是怎么回事吗?我是WPF的新手,并通过绑定将Forms项目迁移到WPF。我正在使用AvalonDock,但没有直接绑定到任何AvalonDock控件。这是几个摘录。为了简洁起见,我删除了很多内容,但如果您需要查看其他内容,请告诉我。
编辑:这两个StackPanels只是测试...试图弄清楚这些东西。
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
属性,并有助于读取中的collections-of-collections Entity
。
编辑3:
我也尝试了一些资源。这是我做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}" />
您的第一个堆栈面板不起作用,因为数据上下文是继承的。因此,一旦将Grid的DataContext更改为ActiveEntity
对象,则在第一个数据上下文中的文本块上的绑定会将TextBlock的datacontext设置为ActiveEntity
当前数据上下文上的,该文本已经是ActiveEntity
(因此ActiveEntity.ActiveEntity
)并且可以尝试绑定到该标签的属性。例如ActiveEntity.ActiveEntity.Label
单击之前,您正在将该窗口的DataContext设置为“ this”,我假设它不是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
and MainWindowViewModel
,至少这是约定,通常您只需在构造函数中设置一次窗口的数据上下文(可以在Loaded
处理程序中设置),在大多数情况下,您无需手动更改后面代码中的任何框架元素。
编辑:示例代码:
MainWindow.xaml
<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>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
}
MainWindowViewModel.cs(为简单起见,省略了INotifyPropertChanged)
public class MainWindowViewModel
{
public EntityViewModel ActiveEntity { get; set; }
}
EntityViewModel.cs(为简单起见,省略了INotifyPropertChanged)
public class EntityViewModel
{
public string Label { get; set; }
}
如您所见,我将Window的DataContext设置为MainViewModel,因此DataContext(所有绑定的根)是MainViewModel,每个TextBlock需要首先访问该ActiveEntity
属性,然后才能访问属性Label
。
另一个选择是,如果您给我们的主堆栈面板中的所有内容都将绑定到ActiveEntity,则可以更改该StackPanel的DataContext,将其绑定到ActiveEntity
,因此其所有子级datacontext也将是该对象。
<StackPanel Orientation="Vertical"
**DataContext="{Binding ActiveEntity}"**>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Label" />
<TextBlock **Text="{Binding Label}"**/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Label Again" />
<TextBlock **Text="{Binding Label}"** />
</StackPanel>
</StackPanel>
编辑2-建议
您应该避免按名称引用对象,并且如果有的话,在其背后的代码中也应尽量少包含逻辑。对于大多数简单的屏幕,除了DataContext的初始绑定之外,不需要在代码中包含任何其他内容(如果您没有创建+设置Windows的DataContext的窗口服务)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句