wpf使用XAML进行数据绑定无法正常工作

时间:2015-12-23 18:30:53

标签: wpf xaml inotifypropertychanged

我正在开发一个用于学习目的的小型应用程序。我发现当我将ItemControl的ItemSource绑定到XAML中的ViewModel属性时,它并没有以预期的方式工作。即它在加载时加载带有值的底层集合,但不会反映对它的任何更改。 但是,如果我在Codebehind中设置Itemsource,它就可以工作。

加载表单时,它会显示2个注释对象。单击按钮应显示第3个。我不明白为什么使用XAML设置DataContext不会更新集合中的更改。我在这里分享代码片段。非常感谢任何帮助。

XAML的缩减版 -

<Window x:Class="NotesApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:NotesApp"
        xmlns:vm="clr-namespace:NotesApp.ViewModel"
        Title="MainWindow" Height="480" Width="640">
    <Window.DataContext >
        <vm:MainViewModel/>
    </Window.DataContext>
    <DockPanel >
        <ScrollViewer VerticalScrollBarVisibility="Auto">
            <ItemsControl Name="NoteItemControl" ItemsSource="{Binding notes}" Background="Beige" >
                <ItemsControl.LayoutTransform>
                    <ScaleTransform ScaleX="{Binding Value, ElementName=zoomSlider}" ScaleY="{Binding Value, ElementName=zoomSlider}" />
                </ItemsControl.LayoutTransform>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Border Name="NoteBorder" Background="Green" CornerRadius="3" Margin="5,3,5,3">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition/>
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <TextBlock Text="{Binding noteText}" Margin="5,3,5,3"/>
                                <StackPanel Grid.Row="1" Orientation="Vertical" >
                                    <Line X1="0" Y1="0" X2="{Binding ActualWidth,ElementName=NoteBorder}" Y2="0" Stroke="Black" StrokeThickness="1"/>
                                    <TextBlock Text="{Binding Category}" Margin="5,3,5,3"/>
                                </StackPanel>
                            </Grid>
                        </Border>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </DockPanel>
</Window>

查看背后的代码 -

namespace NotesApp
{
    public partial class MainWindow : Window
    {
        MainViewModel ViewModel { get; set; }
        public MainWindow()
        {
            InitializeComponent();
            ViewModel = new MainViewModel();
         //  IT WORKS IF I BRING IN THIS STATEMENT 
            //NoteItemControl.ItemsSource = ViewModel.notes;
        }
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            ViewModel.AddNote(new Note("note3", "Category 3"));
        }
    }
}

ViewModel -

namespace NotesApp.ViewModel
{ 
    public class MainViewModel: INotifyPropertyChanged
    {
        ObservableCollection<Note> _notes;
        public ObservableCollection<Note> notes 
        {
            get
            { return _notes; }
            set
            {
                _notes = value;
                OnPropertyChanged("notes");
            }
        }
        public void AddNote(Note note)
        {
            _notes.Add(note);
            OnPropertyChanged("notes");
        }
        public MainViewModel ()
        {
            notes = new ObservableCollection<Note>();
            notes.Add(new Note("note1", "Category 1"));
            notes.Add(new Note("note2", "Category 2"));
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        protected virtual void OnPropertyChanged(string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) 
                handler(this, new PropertyChangedEventArgs( propertyName));
        }
    }
}

2 个答案:

答案 0 :(得分:1)

您创建一个MainViewModel实例并将其分配给XAML中的MainWindow DataContext

<Window.DataContext >
    <vm:MainViewModel/>
</Window.DataContext>

XAML中的绑定使用此实例作为其源对象,只要您没有明确指定其他源。因此,不需要(并且这是一个错误)在后面的代码中创建另一个实例。

更改MainWindow的构造函数,如下所示:

public MainWindow()
{
    InitializeComponent();
    ViewModel = (MainViewModel)DataContext;
}

答案 1 :(得分:0)

试试这个:

&#13;
&#13;
<Window.Resources>
        <vm:MainViewModel x:Key="mainVM"/>
</Window.Resources>
&#13;
&#13;
&#13;

现在使用此密钥作为静态资源,无论您绑定的内容如何:

&#13;
&#13;
<ItemsControl Name="NoteItemControl" ItemsSource="{Binding notes,Source={StaticResource mainVM},Mode=TwoWay}" Background="Beige" >
                
&#13;
&#13;
&#13;

如果你这样做,你就不需要任何datacontext