diff --git a/Tests/Tester.WPF/MainWindow.xaml b/Tests/Tester.WPF/MainWindow.xaml index 943e98d..08677b6 100644 --- a/Tests/Tester.WPF/MainWindow.xaml +++ b/Tests/Tester.WPF/MainWindow.xaml @@ -2,8 +2,17 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:modern="http://modernwpf" - Title="TWAIN Data Source Tester" Height="600" Width="900" ResizeMode="CanResizeWithGrip" + xmlns:proj="clr-namespace:Tester.WPF" + Title="{Binding AppTitle}" + Height="600" Width="900" ResizeMode="CanResizeWithGrip" + x:Name="theWindow" Style="{StaticResource AppWindow}"> + + + + + + @@ -19,7 +28,8 @@ @@ -35,11 +45,11 @@ - @@ -51,7 +61,8 @@ FontStyle="Italic"/> - + + - + + + + + - - - + + + + + + + + + + + + + + + diff --git a/Tests/Tester.WPF/MainWindow.xaml.cs b/Tests/Tester.WPF/MainWindow.xaml.cs index a9a9c04..96eb449 100644 --- a/Tests/Tester.WPF/MainWindow.xaml.cs +++ b/Tests/Tester.WPF/MainWindow.xaml.cs @@ -1,5 +1,6 @@ using GalaSoft.MvvmLight.Messaging; using ModernWPF.Controls; +using ModernWPF.Messages; using NTwain; using NTwain.Data; using System; @@ -26,29 +27,20 @@ namespace Tester.WPF InitializeComponent(); if (!DesignerProperties.GetIsInDesignMode(this)) { - if (PlatformInfo.Current.IsApp64Bit) - { - Title = Title + " (64bit)"; - } - else - { - Title = Title + " (32bit)"; - } - - _twainVM = new TwainVM(); - this.DataContext = _twainVM; + _twainVM = this.DataContext as TwainVM; + Messenger.Default.Register(this, m => m.HandleRefreshCommands()); Messenger.Default.Register(this, msg => { if (Dispatcher.CheckAccess()) { - ModernMessageBox.Show(this, msg.Content, msg.Caption, msg.Button, msg.Icon, msg.DefaultResult); + this.HandleDialogMessageModern(msg); } else { Dispatcher.BeginInvoke(new Action(() => { - ModernMessageBox.Show(this, msg.Content, msg.Caption, msg.Button, msg.Icon, msg.DefaultResult); + this.HandleDialogMessageModern(msg); })); } }); @@ -61,48 +53,16 @@ namespace Tester.WPF } protected override void OnClosed(EventArgs e) { - if (_twainVM.State == 4) - { - _twainVM.CurrentSource.Close(); - } - _twainVM.Close(); + _twainVM.CloseDown(); base.OnClosed(e); } protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); + _twainVM.WindowHandle = new WindowInteropHelper(this).Handle; - // use this for internal msg loop - //var rc = _twainVM.Open(); - - // use this to hook into current app loop - var rc = _twainVM.Open(new WpfMessageLoopHook(new WindowInteropHelper(this).Handle)); - - if (rc == ReturnCode.Success) - { - SrcList.ItemsSource = _twainVM.Select(s => new DSVM { DS = s }); - } } - private void Button_Click_1(object sender, RoutedEventArgs e) - { - _twainVM.TestCapture(new WindowInteropHelper(this).Handle); - } - - private void SrcList_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (_twainVM.State == 4) - { - _twainVM.CurrentSource.Close(); - } - - var dsId = SrcList.SelectedItem as DSVM; - if (dsId != null) - { - dsId.Open(); - } - } - private void CapList_SelectionChanged(object sender, SelectionChangedEventArgs e) { diff --git a/Tests/Tester.WPF/Tester.WPF.csproj b/Tests/Tester.WPF/Tester.WPF.csproj index a45d667..f745f83 100644 --- a/Tests/Tester.WPF/Tester.WPF.csproj +++ b/Tests/Tester.WPF/Tester.WPF.csproj @@ -59,10 +59,22 @@ False ..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll + + ..\..\packages\Microsoft.WindowsAPICodePack-Core.1.1.0.0\lib\Microsoft.WindowsAPICodePack.dll + + + ..\..\packages\Microsoft.WindowsAPICodePack-Shell.1.1.0.0\lib\Microsoft.WindowsAPICodePack.Shell.dll + + + ..\..\packages\Microsoft.WindowsAPICodePack-Shell.1.1.0.0\lib\Microsoft.WindowsAPICodePack.ShellExtensions.dll + False ..\..\packages\ModernWPF.1.2.9.1\lib\net40-Client\ModernWPF.dll + + ..\..\packages\ModernWPF.Mvvm.0.7.0\lib\net40-Client\ModernWPF.Mvvm.dll + @@ -103,7 +115,7 @@ Code - + MainWindow.xaml Code diff --git a/Tests/Tester.WPF/ViewModels/DSVM.cs b/Tests/Tester.WPF/ViewModels/DataSourceVM.cs similarity index 96% rename from Tests/Tester.WPF/ViewModels/DSVM.cs rename to Tests/Tester.WPF/ViewModels/DataSourceVM.cs index 3ad0b26..0f75562 100644 --- a/Tests/Tester.WPF/ViewModels/DSVM.cs +++ b/Tests/Tester.WPF/ViewModels/DataSourceVM.cs @@ -12,7 +12,7 @@ namespace Tester.WPF /// /// Wraps a data source as view model. /// - class DSVM : ViewModelBase + class DataSourceVM : ViewModelBase { public DataSource DS { get; set; } @@ -21,7 +21,7 @@ namespace Tester.WPF public string Protocol { get { return DS.ProtocolVersion.ToString(); } } ICollectionView _capView; - public DSVM() + public DataSourceVM() { Caps = new ObservableCollection(); _capView = CollectionViewSource.GetDefaultView(Caps); diff --git a/Tests/Tester.WPF/ViewModels/TwainVM.cs b/Tests/Tester.WPF/ViewModels/TwainVM.cs index 6148965..ee90526 100644 --- a/Tests/Tester.WPF/ViewModels/TwainVM.cs +++ b/Tests/Tester.WPF/ViewModels/TwainVM.cs @@ -9,39 +9,216 @@ using System.Reflection; using System.Threading; using System.Windows.Media; using System.Windows.Media.Imaging; +using System.Collections.ObjectModel; +using GalaSoft.MvvmLight; +using System.Windows.Input; +using GalaSoft.MvvmLight.Command; +using ModernWPF; +using ModernWPF.Messages; namespace Tester.WPF { /// /// Wraps the twain session as a view model for databinding. /// - class TwainVM : TwainSession + class TwainVM : ViewModelBase { public TwainVM() - : base(TWIdentity.CreateFromAssembly(DataGroups.Image | DataGroups.Audio, Assembly.GetEntryAssembly())) { + DataSources = new ObservableCollection(); + CapturedImages = new ObservableCollection(); + //this.SynchronizationContext = SynchronizationContext.Current; + var appId = TWIdentity.CreateFromAssembly(DataGroups.Image | DataGroups.Audio, Assembly.GetEntryAssembly()); + _session = new TwainSession(appId); + _session.TransferError += _session_TransferError; + _session.TransferReady += _session_TransferReady; + _session.DataTransferred += _session_DataTransferred; + _session.SourceDisabled += _session_SourceDisabled; } - private ImageSource _image; + TwainSession _session; - /// - /// Gets or sets the captured image. - /// - /// - /// The image. - /// - public ImageSource Image + #region properties + + public string AppTitle { - get { return _image; } + get + { + if (NTwain.PlatformInfo.Current.IsApp64Bit) + { + return "TWAIN Data Source Tester (64bit)"; + } + else + { + return "TWAIN Data Source Tester (32bit)"; + } + } + } + public ObservableCollection DataSources { get; private set; } + private DataSourceVM _selectedSource; + + public DataSourceVM SelectedSource + { + get { return _selectedSource; } set { - _image = value; - OnPropertyChanged("Image"); + if (_session.State == 4) + { + _session.CurrentSource.Close(); + } + _selectedSource = value; + RaisePropertyChanged(() => SelectedSource); + if (_selectedSource != null) + { + _selectedSource.Open(); + } } } - protected override void OnTransferError(TransferErrorEventArgs e) + public int State { get { return _session.State; } } + + private IntPtr _winHandle; + public IntPtr WindowHandle + { + get { return _winHandle; } + set + { + _winHandle = value; + if (value == IntPtr.Zero) + { + + } + else + { + // use this for internal msg loop + var rc = _session.Open(); + + // use this to hook into current app loop + //var rc = _session.Open(new WpfMessageLoopHook(value)); + + if (rc == ReturnCode.Success) + { + ReloadSourcesCommand.Execute(null); + } + } + } + } + + + private ICommand _showDriverCommand; + public ICommand ShowDriverCommand + { + get + { + return _showDriverCommand ?? (_showDriverCommand = new RelayCommand(() => + { + if (_session.State == 4) + { + var rc = _session.CurrentSource.Enable(SourceEnableMode.ShowUIOnly, false, WindowHandle); + } + }, () => + { + return _session.State == 4 && _session.CurrentSource.CapEnableDSUIOnly.GetCurrent() == BoolType.True; + })); + } + } + + private ICommand _captureCommand; + public ICommand CaptureCommand + { + get + { + return _captureCommand ?? (_captureCommand = new RelayCommand(() => + { + if (_session.State == 4) + { + //if (this.CurrentSource.ICapPixelType.Get().Contains(PixelType.BlackWhite)) + //{ + // this.CurrentSource.ICapPixelType.Set(PixelType.BlackWhite); + //} + + //if (this.CurrentSource.ICapXferMech.Get().Contains(XferMech.File)) + //{ + // this.CurrentSource.ICapXferMech.Set(XferMech.File); + //} + + var rc = _session.CurrentSource.Enable(SourceEnableMode.NoUI, false, WindowHandle); + } + }, () => + { + return _session.State == 4; + })); + } + } + + + private ICommand _clearCommand; + public ICommand ClearCommand + { + get + { + return _clearCommand ?? (_clearCommand = new RelayCommand(() => + { + CapturedImages.Clear(); + }, () => + { + return CapturedImages.Count > 0; + })); + } + } + private ICommand _reloadSrc; + public ICommand ReloadSourcesCommand + { + get + { + return _reloadSrc ?? (_reloadSrc = new RelayCommand(() => + { + DataSources.Clear(); + foreach (var s in _session.Select(s => new DataSourceVM { DS = s })) + { + DataSources.Add(s); + } + }, () => + { + return _session.State > 2; + })); + } + } + + /// + /// Gets the captured images. + /// + /// + /// The captured images. + /// + public ObservableCollection CapturedImages { get; private set; } + + public double MinThumbnailSize { get { return 50; } } + public double MaxThumbnailSize { get { return 300; } } + + private double _thumbSize = 150; + public double ThumbnailSize + { + get { return _thumbSize; } + set + { + if (value > MaxThumbnailSize) { value = MaxThumbnailSize; } + else if (value < MinThumbnailSize) { value = MinThumbnailSize; } + _thumbSize = value; + RaisePropertyChanged(() => ThumbnailSize); + } + } + + + #endregion + + void _session_SourceDisabled(object sender, EventArgs e) + { + Messenger.Default.Send(new RefreshCommandsMessage()); + } + + void _session_TransferError(object sender, TransferErrorEventArgs e) { App.Current.Dispatcher.BeginInvoke(new Action(() => { @@ -66,25 +243,23 @@ namespace Tester.WPF })); } - protected override void OnTransferReady(TransferReadyEventArgs e) + void _session_TransferReady(object sender, TransferReadyEventArgs e) { - // set it up to use file xfer - - if (this.CurrentSource.CapGetCurrent(CapabilityId.ICapXferMech).ConvertToEnum() == XferMech.File) + if (_session.CurrentSource.ICapXferMech.GetCurrent() == XferMech.File) { - var formats = this.CurrentSource.ICapImageFileFormat.Get(); + var formats = _session.CurrentSource.ICapImageFileFormat.Get(); var wantFormat = formats.Contains(FileFormat.Tiff) ? FileFormat.Tiff : FileFormat.Bmp; var fileSetup = new TWSetupFileXfer { Format = wantFormat, - FileName = GetUniqueName(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test", ".tif") + FileName = GetUniqueName(Path.GetTempPath(), "twain-test", "." + wantFormat) }; - var rc = this.CurrentSource.DGControl.SetupFileXfer.Set(fileSetup); + var rc = _session.CurrentSource.DGControl.SetupFileXfer.Set(fileSetup); } } - private string GetUniqueName(string dir, string name, string ext) + string GetUniqueName(string dir, string name, string ext) { var filePath = Path.Combine(dir, name + ext); int next = 1; @@ -95,9 +270,22 @@ namespace Tester.WPF return filePath; } - protected override void OnDataTransferred(DataTransferredEventArgs e) + void _session_DataTransferred(object sender, DataTransferredEventArgs e) { - ImageSource img = null; + ImageSource img = GenerateThumbnail(e); + if (img != null) + { + App.Current.Dispatcher.BeginInvoke(new Action(() => + { + CapturedImages.Add(img); + })); + } + } + + + ImageSource GenerateThumbnail(DataTransferredEventArgs e) + { + BitmapSource img = null; if (e.NativeData != IntPtr.Zero) { img = e.NativeData.GetWPFBitmap(); @@ -106,35 +294,26 @@ namespace Tester.WPF { img = new BitmapImage(new Uri(e.FileDataPath)); } + if (img != null) { - if (img.CanFreeze) - { - img.Freeze(); - } - App.Current.Dispatcher.BeginInvoke(new Action(() => - { - Image = img; - })); + // from http://stackoverflow.com/questions/18189501/create-thumbnail-image-directly-from-header-less-image-byte-array + var scale = MaxThumbnailSize / img.PixelWidth; + var transform = new ScaleTransform(scale, scale); + var thumbnail = new TransformedBitmap(img, transform); + img = new WriteableBitmap(new TransformedBitmap(img, transform)); + img.Freeze(); } + return img; } - public void TestCapture(IntPtr hwnd) + internal void CloseDown() { - if (State == 4) + if (_session.State == 4) { - //if (this.CurrentSource.ICapPixelType.Get().Contains(PixelType.BlackWhite)) - //{ - // this.CurrentSource.ICapPixelType.Set(PixelType.BlackWhite); - //} - - //if (this.CurrentSource.ICapXferMech.Get().Contains(XferMech.File)) - //{ - // this.CurrentSource.ICapXferMech.Set(XferMech.File); - //} - - var rc = this.CurrentSource.Enable(SourceEnableMode.NoUI, false, hwnd); + _session.CurrentSource.Close(); } + _session.Close(); } } } diff --git a/Tests/Tester.WPF/packages.config b/Tests/Tester.WPF/packages.config index f9a86fc..b52fe3a 100644 --- a/Tests/Tester.WPF/packages.config +++ b/Tests/Tester.WPF/packages.config @@ -2,6 +2,9 @@ + + + \ No newline at end of file