好的,所以这是我的问题: 我有一个WPF应用程序,我正在使用Mvvm模式。在主窗口中,我有一个TabControl,它绑定到一组viewmodel。 Tabcontrol使用contenttemplate使用单独的usercontrol描述每个视图。
现在我想使用按钮将tabcontrol中的每个视图保存到png图像(例如)。问题是 1)如何告诉itemcollection保存每个视图? 2)如何在不特别点击每个tabitem的情况下获取视图(或绑定到各自的datacontext)?
我尝试使用消息处理程序来解决第一个问题,但是,由于所有的tabitems都没有绑定到他们的datacontexts,这意味着第二个问题很难解决。
这是一个例子: 我的主要观点模型:
public class MainViewModel : ViewModelBase {
public ObservableCollection<SubViewModel> Units { get; private set; }
public ICommand OnPrintSaveCommand { get; set; }
public MainViewModel() {
Units = new ObservableCollection<SubViewModel>
{
new SubViewModel(1, "Task 1"),
new SubViewModel(2, "Task 2"),
new SubViewModel(3, "Task 3"),
};
OnPrintSaveCommand = new RelayCommand( p => PrintSave());
}
private void PrintSave() {
foreach (var subViewModel in Units) {
subViewModel.OnPrintSave("SomeFileName.bmp");
}
}
}
然后我有子视图模型:
public delegate void SaveToPngEventHandler(object sender, SaveToPngEventArgs eventArgs);
public class SubViewModel : ViewModelBase {
public int UnitNumber { get; private set; }
public string Unitname { get; private set; }
private event SaveToPngEventHandler SaveToPngHandler;
public SaveToPngEventHandler OnSaveToPng { get { return SaveToPngHandler; } set { SaveToPngHandler = value; } }
public SubViewModel(int unitNumber, string unitname) {
UnitNumber = unitNumber;
Unitname = unitname;
DisplayName = string.Format("{0} - {1}", unitNumber, unitname);
}
public void OnPrintSave(string somefilenameBmp) {
if (OnSaveToPng != null) {
OnSaveToPng(this, new SaveToPngEventArgs(somefilenameBmp));
}
}
}
最后是主窗口:
<Window.Resources>
<DataTemplate x:Key="UnitTemplate" DataType="local:SubViewModel">
<local:ItemView/>
</DataTemplate>
<Style TargetType="TabItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border x:Name="Border" CornerRadius="5,0,0,5" BorderBrush="Black" BorderThickness="1" Margin="10">
<Grid x:Name="grd">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="tb1" Grid.Column="0" Text="{Binding DisplayName}" Margin="2"/>
<TextBlock x:Name="tb2" Grid.Column="1" Text="{Binding UnitNumber}" Margin="2"/>
<TextBlock x:Name="tb3" Grid.Column="2" Text="{Binding Unitname}" Margin="2"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="Blue"/>
<Setter TargetName="tb1" Property="Foreground" Value="White"/>
<Setter TargetName="tb2" Property="Foreground" Value="White"/>
<Setter TargetName="tb3" Property="Foreground" Value="White"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TabControl Grid.Row="0" ItemsSource="{Binding Units}" TabStripPlacement="Left" ContentTemplate="{StaticResource UnitTemplate}"/>
<Button Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Right" Content="Print/save" Margin="5" Command="{Binding OnPrintSaveCommand}"></Button>
</Grid>
和subviewmodel的单独viewcontrol:
<Grid x:Name="MainGrid">
<Border CornerRadius="5" BorderBrush="Black" BorderThickness="1" Margin="10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding DisplayName}" Margin="10"/>
<TextBlock Grid.Column="1" Text="{Binding UnitNumber}" Margin="10"/>
<TextBlock Grid.Column="2" Text="{Binding Unitname}" Margin="10"/>
</Grid>
</Border>
</Grid>
后面的代码:
/// <summary>
/// Interaction logic for ItemView.xaml
/// </summary>
public partial class ItemView : UserControl {
public ItemView() {
InitializeComponent();
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs) {
var viewModel = DataContext as SubViewModel;
if (viewModel != null) {
viewModel.OnSaveToPng += OnSaveToPng;
// Will only reach this point if tabitem has been clicked
}
}
private void OnSaveToPng(object sender, SaveToPngEventArgs eventArgs) {
// Get MainGrid and save it here
var canvas = new Canvas();
//canvas.Children.Add(MainGrid);
// etc..
}
}
为了运行它,您还需要以下类:
public class RelayCommand : ICommand {
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null) {
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute) {
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter) {
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter) {
_execute(parameter);
}
#endregion // ICommand Members
}
public class ViewModelBase : INotifyPropertyChanged {
public string DisplayName { get; set; }
#region Property Changed
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
public class SaveToPngEventArgs : EventArgs {
public string FilePath { get; private set; }
public SaveToPngEventArgs(string filePath) {
FilePath = filePath;
}
}