WPF窗口未在XAML中使用绑定进行更新

时间:2015-01-03 22:47:00

标签: c# wpf

有人可以解释一下这里发生了什么吗?我是WPF的新手,并通过绑定将我的Forms项目迁移到WPF。我正在使用AvalonDock,但我没有直接绑定到任何AvalonDock控件。这是一些摘录。为了简洁起见,我删除了很多,但如果你需要看别的东西,请告诉我。

编辑:这两个StackPanel只是测试...试图弄清楚这些东西。
EDIT2 :我最终试图做MVVM;我只需要更好地处理绑定,所以我知道如何构建它 EDIT3 :见帖子的底部。

问:第一个StackPanel根本没有更新,更不用说更改后更新了。我尝试在DataContextStackPanelGrid中设置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";
}

EntityEntityViewModel实施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}" />

2 个答案:

答案 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。

你将会有一个MainWindowViewMainWindowViewModel,至少这是惯例,通常你会在构造函数中设置一次窗口的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的窗口服务)