WPF更新DataBinding

时间:2015-07-29 12:58:20

标签: c# wpf xaml data-binding

所以,我测试了很多我在不同主题上找到的答案,但我的WPF应用程序仍然没有更新绑定数据。当我在正确显示MainWindow数据之前设置所有属性时,我需要在加载数据之前选择目录,日期等。试图在代码中改变DataContext,但IT不起作用。用作VieModel的所有类都实现了INotifyPropertyChanged接口(但PropertyChanged值始终为null)。我现在没有想法......

这是XAML代码:

<Window x:Class="WpfDataBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfDataBinding"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="800" Name="Logs">
    <Window.DataContext>
        <local:CustomDataContexts />
    </Window.DataContext>
    <Grid Name="Logi">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <local:CustomButton Grid.Column="0" Grid.Row="1" Margin="5" Height="35" Width="100" x:Name="Choose" Text="Wybierz:" ImageSource="Resources/choose.png" Click="CustomButton_Click" />
        <local:CustomButton Grid.Column="0" Grid.Row="2" Margin="5" Height="35" Width="100" x:Name="Load" Text="Załaduj:" ImageSource="Resources/load.png" Click="CustomButton_Click" />
        <local:CustomButton Grid.Column="0" Grid.Row="3" Margin="5" Height="35" Width="100" x:Name="Search" Text="Szukaj:" ImageSource="Resources/search.png" Click="CustomButton_Click" />
        <local:CustomButton Grid.Column="3" Grid.Row="2" Margin="5" Height="80" Width="100" x:Name="Next" Grid.RowSpan="2" Text="Dalej:" ImageSource="Resources/next.png" Click="CustomButton_Click" />
        <TabControl DataContext="{Binding TextViewModel}" x:Name="tabControl" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding TxtView.Tabs, ElementName=Logs, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
            <TabControl.ItemTemplate>
                <!-- this is the header template-->
                <DataTemplate>
                    <TextBlock Text="{Binding Header}" />
                </DataTemplate>
            </TabControl.ItemTemplate>
            <TabControl.ContentTemplate >
                <!-- this is the body of the TabItem template-->
                <DataTemplate>
                    <ListView ItemsSource="{Binding EntryViewModels}">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Entry.Tag}"/>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
        <TabControl DataContext="{Binding SingleNode}" x:Name="tabControl2" Grid.Row="0" Grid.Column="2"  Grid.ColumnSpan="2" ItemsSource="{Binding Tabs}">
            <TabControl.ItemTemplate>
                <!-- this is the header template-->
                <DataTemplate>
                    <TextBlock Text="{Binding Header}" />
                </DataTemplate>
            </TabControl.ItemTemplate>
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <ListView ItemsSource="{Binding Content}" />
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </Grid>
</Window>

代码隐藏看起来像这样:

    public CustomDataContexts DataContexts { get; set; }
    public string Path { get; set; }
    public Files Files { get; set; }

    public MainWindow()
    {
        /*Path = @"C:\Users\Slawek\Desktop\Logs\logi";
        Files = new Files(Path);
        Files.NarrowFiles(false, DateTime.MinValue);
        var entry = new EntryCollection(Files.SelectedFiles[1], Files.SelectedFiles, null);
        TxtView = new TxtViewModel(new List<TxtTabItem>(new[] { new TxtTabItem(entry) }));*/
        InitializeComponent();
    }

    private void CustomButton_Click(object sender, RoutedEventArgs e)
    {
        var fe = (FrameworkElement) sender;
        switch (fe.Name)
        {
            case "Choose":
                var g = new FolderBrowserDialog();
                if (g.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    Path = g.SelectedPath;
                break;
            case "Load":
                DataContexts = new CustomDataContexts();
                Files = new Files(Path);
                Files.NarrowFiles(false, DateTime.MinValue);
                var entry = new EntryCollection(Files.SelectedFiles[1], Files.SelectedFiles, null);
                DataContexts.TextViewModel = new TxtViewModel(new List<TxtTabItem>(new[] { new TxtTabItem(entry) }));
                break;
            case "Search":
                break;
            case "Next":
                break;
        }
    }

CustomDataContexts类:

public class CustomDataContexts : INotifyPropertyChanged
{
    private TxtViewModel textViewModel;
    public XmlViewModel SingleNode { get; set; }

    public TxtViewModel TextViewModel
    {
        get { return textViewModel; }
        set { OnPropertyChanged("TextViewModel"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

EntryViewModel:

public class EntryViewModel : INotifyPropertyChanged
{
    private SingleEntry entry;

    public SingleEntry Entry
    {
        get { return entry; }
        set 
        {
            entry = value;
            OnPropertyChanged("Entry");
        }
    }

    public EntryViewModel(SingleEntry entry)
    {
        Entry = entry;
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

TxtViewModel:

public class TxtViewModel :INotifyPropertyChanged
{
    private ObservableCollection <TxtTabItem> tabs;

    public ObservableCollection<TxtTabItem> Tabs
    {
        get { return tabs; }
        set
        { 
            tabs = value;
            OnPropertyChanged("Tabs");
        }
    }

    public TxtViewModel(List<TxtTabItem> items)
    {
        Tabs = new ObservableCollection <TxtTabItem>();
        foreach (var txtTabItem in items)
        {
            Tabs.Add(txtTabItem);
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

最后是TxtTabItem类:

public class TxtTabItem : INotifyPropertyChanged
{
    public string Header { get; set; }
    public ObservableCollection<EntryViewModel> EntryViewModels { get; set; }

    public TxtTabItem(EntryCollection collection)
    {
        Header = collection.Date.ToShortDateString();
        EntryViewModels = new ObservableCollection <EntryViewModel>();
        foreach (var entry in collection.Entries)
        {
            EntryViewModels.Add(new EntryViewModel(entry));
        }
        OnPropertyChanged("EntryViewModels");
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

我将非常感谢有关如何使此代码工作的任何建议。我对WPF很新,但仍然不太了解它。

1 个答案:

答案 0 :(得分:0)

框架在那里,但通常初始化控件以更改一个绑定到ItemsSource属性而不是直接绑定到DataContext。

通常,DataContext提供有关当前项的信息,但是当它为null时,父级的数据上下文将用完,直到页面的数据上下文。

原因是数据上下文将包含大量属性,并且绑定将在DataContext上查找该命名属性( reflect / reflection)。因此,通过使用ItemsSource可以绑定到特定的一组项目,同时仍然有DataContext个完整的信息,以允许控件上的其他项绑定到其他特定属性。

在MVVM中,VM或视图模型是上述属性类,将页面的数据上下文设置为该VM,然后从页面的datacontext绑定到的不同控件上的各个属性

所以

  <TabControl DataContext="{Binding TextViewModel}" x:Name="tabControl" 

变为

  <TabControl ItemsSource="{Binding TextViewModel}" x:Name="tabControl" 

将页面的数据上下文设置为TxtViewModel

我在博客文章Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding上提供了绑定/ VM示例。