| File: MS\Internal\Navigation\BindStream.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // // Description: // Implements a monitored stream so that all calls to the base stream // can be intersected and thereby loading progress can be accurately measured. // using System.IO; using MS.Internal.AppModel; using System.Windows.Threading; //DispatcherObject using System.Windows.Markup; using System.Reflection; namespace MS.Internal.Navigation { #region BindStream Class // Implements a monitored stream so that all calls to the base stream // can be intersected and thereby loading progress can be accurately measured. internal class BindStream : Stream, IStreamInfo { #region Constructors internal BindStream(Stream stream, long maxBytes, Uri uri, IContentContainer cc, Dispatcher callbackDispatcher) { _bytesRead = 0; _maxBytes = maxBytes; _lastProgressEventByte = 0; _stream = stream; _uri = uri; _cc = cc; _callbackDispatcher = callbackDispatcher; } #endregion Constructors #region Private Methods private void UpdateNavigationProgress() { for(long numBytes =_lastProgressEventByte + _bytesInterval; numBytes <= _bytesRead; numBytes += _bytesInterval) { UpdateNavProgressHelper(numBytes); _lastProgressEventByte = numBytes; } if (_bytesRead == _maxBytes && _lastProgressEventByte < _maxBytes) { UpdateNavProgressHelper(_maxBytes); _lastProgressEventByte = _maxBytes; } } private void UpdateNavProgressHelper(long numBytes) { if ((_callbackDispatcher != null) && (!_callbackDispatcher.CheckAccess())) { _callbackDispatcher.BeginInvoke( DispatcherPriority.Send, (DispatcherOperationCallback)delegate(object unused) { _cc.OnNavigationProgress(_uri, numBytes, _maxBytes); return null; }, null); } else { _cc.OnNavigationProgress(_uri, numBytes, _maxBytes); } } #endregion Private Methods #region Overrides #region Overridden Properties /// <summary> /// Overridden CanRead Property /// </summary> public override bool CanRead { get { return _stream.CanRead; } } /// <summary> /// Overridden CanSeek Property /// </summary> public override bool CanSeek { get { return _stream.CanSeek; } } /// <summary> /// Overridden CanWrite Property /// </summary> public override bool CanWrite { get { return _stream.CanWrite; } } /// <summary> /// Overridden Length Property /// </summary> public override long Length { get { return _stream.Length; } } /// <summary> /// Overridden Position Property /// </summary> public override long Position { get { return _stream.Position; } set { _stream.Position = value; } } #endregion Overridden Properties #region Overridden Public Methods /// <summary> /// Overridden BeginRead method /// </summary> /// <param name="buffer"></param> /// <param name="offset"></param> /// <param name="count"></param> /// <param name="callback"></param> /// <param name="state"></param> /// <returns></returns> public override IAsyncResult BeginRead( byte[] buffer, int offset, int count, AsyncCallback callback, object state ) { return _stream.BeginRead(buffer, offset, count, callback, state); } /// <summary> /// Overridden BeginWrite method /// </summary> /// <param name="buffer"></param> /// <param name="offset"></param> /// <param name="count"></param> /// <param name="callback"></param> /// <param name="state"></param> /// <returns></returns> public override IAsyncResult BeginWrite( byte[] buffer, int offset, int count, AsyncCallback callback, object state ) { return _stream.BeginWrite(buffer, offset, count, callback, state); } /// <summary> /// Overridden Close method /// </summary> public override void Close() { _stream.Close(); // if current dispatcher is not the same as the dispatcher we should call back on, // post to the call back dispatcher. if ((_callbackDispatcher != null) && (!_callbackDispatcher.CheckAccess())) { _callbackDispatcher.BeginInvoke( DispatcherPriority.Send, (DispatcherOperationCallback)delegate(object unused) { _cc.OnStreamClosed(_uri); return null; }, null); } else { _cc.OnStreamClosed(_uri); } } /// <summary> /// Overridden EndRead method /// </summary> /// <param name="asyncResult"></param> /// <returns></returns> public override int EndRead( IAsyncResult asyncResult ) { return _stream.EndRead(asyncResult); } /// <summary> /// Overridden EndWrite method /// </summary> /// <param name="asyncResult"></param> public override void EndWrite( IAsyncResult asyncResult ) { _stream.EndWrite(asyncResult); } /// <summary> /// Overridden Equals method /// </summary> /// <param name="obj"></param> /// <returns></returns> public override bool Equals( object obj ) { return _stream.Equals(obj); } /// <summary> /// Overridden Flush method /// </summary> public override void Flush() { _stream.Flush(); } /// <summary> /// Overridden GetHashCode method /// </summary> /// <returns></returns> public override int GetHashCode() { return _stream.GetHashCode(); } /*/// <summary> /// GetLifetimeService method /// </summary> /// <returns></returns> // Do we want this method here? public new object GetLifetimeService() { return _stream.GetLifetimeService(); } /// <summary> /// GetType method /// </summary> /// <returns></returns> // Do we want this method here? public new Type GetType() { return _stream.GetType(); }*/ /// <summary> /// Overridden InitializeLifetimeService method /// </summary> /// <returns></returns> [ObsoleteAttribute("InitializeLifetimeService is obsolete.", false)] public override object InitializeLifetimeService() { return _stream.InitializeLifetimeService(); } /// <summary> /// Overridden Read method /// </summary> /// <param name="buffer"></param> /// <param name="offset"></param> /// <param name="count"></param> /// <returns></returns> public override int Read( byte[] buffer, int offset, int count ) { int bytes = _stream.Read(buffer, offset, count); _bytesRead += bytes; //File, http, stream resources all seem to pass in a valid maxbytes. //Incase loading compressed container or asp files serving out content cause maxbytes //to be not known upfront or a webserver does not send a content length(does http spec mandate it), //update the maxbytes dynamically here. Also if we reach the end of the download stream //force a NavigationProgress event with the last set of bytes and the final maxbytes value _maxBytes = _bytesRead > _maxBytes ? _bytesRead : _maxBytes; //Make sure the final notification is sent incase _maxBytes falls below the interval boundary if (((_lastProgressEventByte + _bytesInterval) <= _bytesRead) || bytes == 0) { UpdateNavigationProgress(); } return bytes; } /// <summary> /// Overridden ReadByte method /// </summary> /// <returns></returns> public override int ReadByte() { int val = _stream.ReadByte(); if (val != -1) { _bytesRead++; _maxBytes = _bytesRead > _maxBytes ? _bytesRead : _maxBytes; } //Make sure the final notification is sent incase _maxBytes falls below the interval boundary if (((_lastProgressEventByte + _bytesInterval) <= _bytesRead) || val == -1) { UpdateNavigationProgress(); } return val; } /// <summary> /// Overridden Seek method /// </summary> /// <param name="offset"></param> /// <param name="origin"></param> /// <returns></returns> public override long Seek( long offset, SeekOrigin origin ) { return _stream.Seek(offset, origin); } /// <summary> /// Overridden SetLength method /// </summary> /// <param name="value"></param> public override void SetLength( long value ) { _stream.SetLength(value); } /// <summary> /// Overridden ToString method /// </summary> /// <returns></returns> public override string ToString() { return _stream.ToString(); } /// <summary> /// Overridden Write method /// </summary> /// <param name="buffer"></param> /// <param name="offset"></param> /// <param name="count"></param> public override void Write( byte[] buffer, int offset, int count ) { _stream.Write(buffer, offset, count); } /// <summary> /// Overridden WriteByte method /// </summary> /// <param name="value"></param> public override void WriteByte( byte value ) { _stream.WriteByte(value); } #endregion Overridden Public Methods #endregion Overrides #region Properties /// <summary> /// Underlying Stream of BindStream /// </summary> public Stream Stream { get { return _stream; } } // // Assembly which contains the stream data. // Assembly IStreamInfo.Assembly { get { Assembly assembly = null; if (_stream != null) { IStreamInfo streamInfo = _stream as IStreamInfo; if (streamInfo != null) { assembly = streamInfo.Assembly; } } return assembly; } } #endregion Properties #region Private Data private long _bytesRead; private long _maxBytes; private long _lastProgressEventByte; private Stream _stream; private Uri _uri; private IContentContainer _cc; private Dispatcher _callbackDispatcher; private const long _bytesInterval = 1024; #endregion Private Data } #endregion BindStream Class }