所以,我测试了很多我在不同主题上找到的答案,但我的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很新,但仍然不太了解它。
答案 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示例。