Pushing missing changes

This commit is contained in:
LukePulverenti
2013-02-20 20:33:05 -05:00
parent 845554722e
commit 767cdc1f6f
924 changed files with 103121 additions and 18677 deletions

View File

@@ -0,0 +1,62 @@
using System;
using System.Windows;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// Class BaseModalWindow
/// </summary>
public class BaseModalWindow : BaseWindow
{
/// <summary>
/// Shows the modal.
/// </summary>
/// <param name="owner">The owner.</param>
public void ShowModal(Window owner)
{
WindowStyle = WindowStyle.None;
ResizeMode = ResizeMode.NoResize;
ShowInTaskbar = false;
WindowStartupLocation = WindowStartupLocation.Manual;
AllowsTransparency = true;
Width = owner.Width;
Height = owner.Height;
Top = owner.Top;
Left = owner.Left;
WindowState = owner.WindowState;
Owner = owner;
ShowDialog();
}
/// <summary>
/// Called when [browser back].
/// </summary>
protected override void OnBrowserBack()
{
base.OnBrowserBack();
CloseModal();
}
/// <summary>
/// Raises the <see cref="E:System.Windows.FrameworkElement.Initialized" /> event. This method is invoked whenever <see cref="P:System.Windows.FrameworkElement.IsInitialized" /> is set to true internally.
/// </summary>
/// <param name="e">The <see cref="T:System.Windows.RoutedEventArgs" /> that contains the event data.</param>
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
DataContext = this;
}
/// <summary>
/// Closes the modal.
/// </summary>
protected virtual void CloseModal()
{
Close();
}
}
}

View File

@@ -0,0 +1,21 @@
using System.ComponentModel;
using System.Windows.Controls;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// Provides a base class for all user controls
/// </summary>
public abstract class BaseUserControl : UserControl
{
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
}

View File

@@ -0,0 +1,175 @@
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// Provides a base class for all Windows
/// </summary>
public abstract class BaseWindow : Window, INotifyPropertyChanged
{
/// <summary>
/// Occurs when [property changed].
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Called when [property changed].
/// </summary>
/// <param name="info">The info.</param>
public void OnPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
/// <summary>
/// The _content scale
/// </summary>
private double _contentScale = 1;
/// <summary>
/// Gets the content scale.
/// </summary>
/// <value>The content scale.</value>
public double ContentScale
{
get { return _contentScale; }
private set
{
_contentScale = value;
OnPropertyChanged("ContentScale");
}
}
/// <summary>
/// Initializes a new instance of the <see cref="BaseWindow" /> class.
/// </summary>
protected BaseWindow()
: base()
{
SizeChanged += MainWindow_SizeChanged;
Loaded += BaseWindowLoaded;
}
/// <summary>
/// Bases the window loaded.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
void BaseWindowLoaded(object sender, RoutedEventArgs e)
{
OnLoaded();
}
/// <summary>
/// Called when [loaded].
/// </summary>
protected virtual void OnLoaded()
{
MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}
/// <summary>
/// Handles the SizeChanged event of the MainWindow control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="SizeChangedEventArgs" /> instance containing the event data.</param>
void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
{
ContentScale = e.NewSize.Height / 1080;
}
/// <summary>
/// Called when [browser back].
/// </summary>
protected virtual void OnBrowserBack()
{
}
/// <summary>
/// Called when [browser forward].
/// </summary>
protected virtual void OnBrowserForward()
{
}
/// <summary>
/// Invoked when an unhandled <see cref="E:System.Windows.Input.Keyboard.PreviewKeyDown" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
/// </summary>
/// <param name="e">The <see cref="T:System.Windows.Input.KeyEventArgs" /> that contains the event data.</param>
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
if (IsBackPress(e))
{
e.Handled = true;
if (!e.IsRepeat)
{
OnBrowserBack();
}
}
else if (IsForwardPress(e))
{
e.Handled = true;
if (!e.IsRepeat)
{
OnBrowserForward();
}
}
base.OnPreviewKeyDown(e);
}
/// <summary>
/// Determines if a keypress should be treated as a backward press
/// </summary>
/// <param name="e">The <see cref="KeyEventArgs" /> instance containing the event data.</param>
/// <returns><c>true</c> if [is back press] [the specified e]; otherwise, <c>false</c>.</returns>
private bool IsBackPress(KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
return true;
}
if (e.Key == Key.BrowserBack || e.Key == Key.Back)
{
return true;
}
if (e.SystemKey == Key.Left && e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Alt))
{
return true;
}
return false;
}
/// <summary>
/// Determines if a keypress should be treated as a forward press
/// </summary>
/// <param name="e">The <see cref="KeyEventArgs" /> instance containing the event data.</param>
/// <returns><c>true</c> if [is forward press] [the specified e]; otherwise, <c>false</c>.</returns>
private bool IsForwardPress(KeyEventArgs e)
{
if (e.Key == Key.BrowserForward)
{
return true;
}
if (e.SystemKey == Key.RightAlt && e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Alt))
{
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,49 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// This subclass simply autofocuses itself when the mouse moves over it
/// </summary>
public class ExtendedButton : Button
{
private Point? _lastMouseMovePoint;
/// <summary>
/// Handles OnMouseMove to auto-select the item that's being moused over
/// </summary>
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
var window = this.GetWindow();
// If the cursor is currently hidden, don't bother reacting to it
if (Cursor == Cursors.None || window.Cursor == Cursors.None)
{
return;
}
// Store the last position for comparison purposes
// Even if the mouse is not moving this event will fire as elements are showing and hiding
var pos = e.GetPosition(window);
if (!_lastMouseMovePoint.HasValue)
{
_lastMouseMovePoint = pos;
return;
}
if (pos == _lastMouseMovePoint)
{
return;
}
_lastMouseMovePoint = pos;
Focus();
}
}
}

View File

@@ -0,0 +1,49 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// Extends Checkbox to provide focus on mouse over
/// </summary>
public class ExtendedCheckbox : CheckBox
{
private Point? _lastMouseMovePoint;
/// <summary>
/// Handles OnMouseMove to auto-select the item that's being moused over
/// </summary>
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
var window = this.GetWindow();
// If the cursor is currently hidden, don't bother reacting to it
if (Cursor == Cursors.None || window.Cursor == Cursors.None)
{
return;
}
// Store the last position for comparison purposes
// Even if the mouse is not moving this event will fire as elements are showing and hiding
var pos = e.GetPosition(window);
if (!_lastMouseMovePoint.HasValue)
{
_lastMouseMovePoint = pos;
return;
}
if (pos == _lastMouseMovePoint)
{
return;
}
_lastMouseMovePoint = pos;
Focus();
}
}
}

View File

@@ -0,0 +1,260 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// Extends the ListBox to provide auto-focus behavior when items are moused over
/// This also adds an ItemInvoked event that is fired when an item is clicked or invoked using the enter key
/// </summary>
public class ExtendedListBox : ListBox
{
/// <summary>
/// Fired when an item is clicked or invoked using the enter key
/// </summary>
public event EventHandler<ItemEventArgs<object>> ItemInvoked;
/// <summary>
/// Called when [item invoked].
/// </summary>
/// <param name="boundObject">The bound object.</param>
protected virtual void OnItemInvoked(object boundObject)
{
if (ItemInvoked != null)
{
ItemInvoked(this, new ItemEventArgs<object> { Argument = boundObject });
}
}
/// <summary>
/// The _auto focus
/// </summary>
private bool _autoFocus = true;
/// <summary>
/// Gets or sets a value indicating if the first list item should be auto-focused on load
/// </summary>
/// <value><c>true</c> if [auto focus]; otherwise, <c>false</c>.</value>
public bool AutoFocus
{
get { return _autoFocus; }
set
{
_autoFocus = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="ExtendedListBox" /> class.
/// </summary>
public ExtendedListBox()
: base()
{
ItemContainerGenerator.StatusChanged += ItemContainerGeneratorStatusChanged;
}
/// <summary>
/// The mouse down object
/// </summary>
private object mouseDownObject;
/// <summary>
/// Invoked when an unhandled <see cref="E:System.Windows.Input.Mouse.PreviewMouseDown" /> attached routed event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
/// </summary>
/// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that contains the event data. The event data reports that one or more mouse buttons were pressed.</param>
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseDown(e);
// Get the item that the mouse down event occurred on
mouseDownObject = GetBoundListItemObject((DependencyObject)e.OriginalSource);
}
/// <summary>
/// Invoked when an unhandled <see cref="E:System.Windows.UIElement.MouseLeftButtonUp" /> routed event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
/// </summary>
/// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that contains the event data. The event data reports that the left mouse button was released.</param>
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
// If the mouse up event occurred on the same item as the mousedown event, then fire ItemInvoked
if (mouseDownObject != null)
{
var boundObject = GetBoundListItemObject((DependencyObject)e.OriginalSource);
if (mouseDownObject == boundObject)
{
mouseDownObject = null;
OnItemInvoked(boundObject);
}
}
}
/// <summary>
/// The key down object
/// </summary>
private object keyDownObject;
/// <summary>
/// Responds to the <see cref="E:System.Windows.UIElement.KeyDown" /> event.
/// </summary>
/// <param name="e">Provides data for <see cref="T:System.Windows.Input.KeyEventArgs" />.</param>
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
if (!e.IsRepeat)
{
// Get the item that the keydown event occurred on
keyDownObject = GetBoundListItemObject((DependencyObject)e.OriginalSource);
}
e.Handled = true;
}
base.OnKeyDown(e);
}
/// <summary>
/// Invoked when an unhandled <see cref="E:System.Windows.Input.Keyboard.KeyUp" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
/// </summary>
/// <param name="e">The <see cref="T:System.Windows.Input.KeyEventArgs" /> that contains the event data.</param>
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
// Fire ItemInvoked when enter is pressed on an item
if (e.Key == Key.Enter)
{
if (!e.IsRepeat)
{
// If the keyup event occurred on the same item as the keydown event, then fire ItemInvoked
if (keyDownObject != null)
{
var boundObject = GetBoundListItemObject((DependencyObject)e.OriginalSource);
if (keyDownObject == boundObject)
{
keyDownObject = null;
OnItemInvoked(boundObject);
}
}
}
e.Handled = true;
}
}
/// <summary>
/// The _last mouse move point
/// </summary>
private Point? _lastMouseMovePoint;
/// <summary>
/// Handles OnMouseMove to auto-select the item that's being moused over
/// </summary>
/// <param name="e">Provides data for <see cref="T:System.Windows.Input.MouseEventArgs" />.</param>
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
var window = this.GetWindow();
// If the cursor is currently hidden, don't bother reacting to it
if (Cursor == Cursors.None || window.Cursor == Cursors.None)
{
return;
}
// Store the last position for comparison purposes
// Even if the mouse is not moving this event will fire as elements are showing and hiding
var pos = e.GetPosition(window);
if (!_lastMouseMovePoint.HasValue)
{
_lastMouseMovePoint = pos;
return;
}
if (pos == _lastMouseMovePoint)
{
return;
}
_lastMouseMovePoint = pos;
var dep = (DependencyObject)e.OriginalSource;
while ((dep != null) && !(dep is ListBoxItem))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (dep != null)
{
var listBoxItem = dep as ListBoxItem;
if (!listBoxItem.IsFocused)
{
listBoxItem.Focus();
}
}
}
/// <summary>
/// Gets the datacontext for a given ListBoxItem
/// </summary>
/// <param name="dep">The dep.</param>
/// <returns>System.Object.</returns>
private object GetBoundListItemObject(DependencyObject dep)
{
while ((dep != null) && !(dep is ListBoxItem))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (dep == null)
{
return null;
}
return ItemContainerGenerator.ItemFromContainer(dep);
}
/// <summary>
/// Autofocuses the first list item when the list is loaded
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
void ItemContainerGeneratorStatusChanged(object sender, EventArgs e)
{
if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated && AutoFocus)
{
Dispatcher.InvokeAsync(OnContainersGenerated);
}
}
/// <summary>
/// Called when [containers generated].
/// </summary>
void OnContainersGenerated()
{
var index = 0;
if (index >= 0)
{
var item = ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem;
if (item != null)
{
item.Focus();
ItemContainerGenerator.StatusChanged -= ItemContainerGeneratorStatusChanged;
}
}
}
}
}

View File

@@ -0,0 +1,49 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// Extends RadioButton to provide focus on mouse over, and invoke on enter press
/// </summary>
public class ExtendedRadioButton : RadioButton
{
private Point? _lastMouseMovePoint;
/// <summary>
/// Handles OnMouseMove to auto-select the item that's being moused over
/// </summary>
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
var window = this.GetWindow();
// If the cursor is currently hidden, don't bother reacting to it
if (Cursor == Cursors.None || window.Cursor == Cursors.None)
{
return;
}
// Store the last position for comparison purposes
// Even if the mouse is not moving this event will fire as elements are showing and hiding
var pos = e.GetPosition(window);
if (!_lastMouseMovePoint.HasValue)
{
_lastMouseMovePoint = pos;
return;
}
if (pos == _lastMouseMovePoint)
{
return;
}
_lastMouseMovePoint = pos;
Focus();
}
}
}

View File

@@ -0,0 +1,41 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// This subclass solves the problem of ScrollViewers eating KeyDown for all arrow keys
/// </summary>
public class ExtendedScrollViewer : ScrollViewer
{
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Handled || e.OriginalSource == this)
{
base.OnKeyDown(e);
return;
}
// Don't eat left/right if horizontal scrolling is disabled
if (e.Key == Key.Left || e.Key == Key.Right)
{
if (HorizontalScrollBarVisibility == ScrollBarVisibility.Disabled)
{
return;
}
}
// Don't eat up/down if vertical scrolling is disabled
if (e.Key == Key.Up || e.Key == Key.Down)
{
if (VerticalScrollBarVisibility == ScrollBarVisibility.Disabled)
{
return;
}
}
// Let the base class do it's thing
base.OnKeyDown(e);
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// Provides a generic EventArgs subclass that can hold any kind of object
/// </summary>
/// <typeparam name="T"></typeparam>
public class ItemEventArgs<T> : EventArgs
{
/// <summary>
/// Gets or sets the argument.
/// </summary>
/// <value>The argument.</value>
public T Argument { get; set; }
}
}

View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1ADFE460-FD95-46FA-8871-CCCB4B62E2E8}</ProjectGuid>
<OutputType>library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MediaBrowser.UI.Controls</RootNamespace>
<AssemblyName>MediaBrowser.UI.Controls</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Expression.Effects">
<HintPath>..\ThirdParty\Expression\Microsoft.Expression.Effects.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Expression.Interactions">
<HintPath>..\ThirdParty\Expression\Microsoft.Expression.Interactions.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Compile Include="BaseModalWindow.cs" />
<Compile Include="BaseUserControl.cs" />
<Compile Include="BaseWindow.cs" />
<Compile Include="ExtendedButton.cs" />
<Compile Include="ExtendedCheckbox.cs" />
<Compile Include="ExtendedListBox.cs" />
<Compile Include="ExtendedRadioButton.cs" />
<Compile Include="ExtendedScrollViewer.cs" />
<Compile Include="ItemEventArgs.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="ScrollingPanel.cs" />
<Compile Include="TransitionControl.cs" />
<Compile Include="TransitionFrame.cs" />
<Compile Include="TreeHelper.cs" />
<Compile Include="VirtualizingWrapPanel.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("MediaBrowser.UI.Controls")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MediaBrowser.UI.Controls")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18033
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MediaBrowser.UI.Controls.Properties {
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if ((resourceMan == null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MediaBrowser.UI.Controls.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18033
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MediaBrowser.UI.Controls.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,404 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// This started from:
/// http://www.switchonthecode.com/tutorials/wpf-tutorial-implementing-iscrollinfo
/// Then, after implementing this, content was being displayed in stack panel like manner.
/// I then reviewed the source code of ScrollContentPresenter and updated MeasureOverride and ArrangeOverride to match.
/// </summary>
public class ScrollingPanel : Grid, IScrollInfo
{
/// <summary>
/// The infinite size
/// </summary>
private static Size InfiniteSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
/// <summary>
/// The line size
/// </summary>
private const double LineSize = 16;
/// <summary>
/// The wheel size
/// </summary>
private const double WheelSize = 3 * LineSize;
/// <summary>
/// The _ offset
/// </summary>
private Vector _Offset;
/// <summary>
/// The _ extent
/// </summary>
private Size _Extent;
/// <summary>
/// The _ viewport
/// </summary>
private Size _Viewport;
/// <summary>
/// The _ animation length
/// </summary>
private TimeSpan _AnimationLength = TimeSpan.FromMilliseconds(125);
/// <summary>
/// When overridden in a derived class, measures the size in layout required for child elements and determines a size for the <see cref="T:System.Windows.FrameworkElement" />-derived class.
/// </summary>
/// <param name="availableSize">The available size that this element can give to child elements. Infinity can be specified as a value to indicate that the element will size to whatever content is available.</param>
/// <returns>The size that this element determines it needs during layout, based on its calculations of child element sizes.</returns>
protected override Size MeasureOverride(Size availableSize)
{
if (Children == null || Children.Count == 0)
{
return availableSize;
}
var constraint2 = availableSize;
if (CanHorizontallyScroll)
{
constraint2.Width = double.PositiveInfinity;
}
if (CanVerticallyScroll)
{
constraint2.Height = double.PositiveInfinity;
}
var uiElement = Children[0];
uiElement.Measure(constraint2);
var size = uiElement.DesiredSize;
VerifyScrollData(availableSize, size);
size.Width = Math.Min(availableSize.Width, size.Width);
size.Height = Math.Min(availableSize.Height, size.Height);
return size;
}
/// <summary>
/// Arranges the content of a <see cref="T:System.Windows.Controls.Grid" /> element.
/// </summary>
/// <param name="arrangeSize">Specifies the size this <see cref="T:System.Windows.Controls.Grid" /> element should use to arrange its child elements.</param>
/// <returns><see cref="T:System.Windows.Size" /> that represents the arranged size of this Grid element and its children.</returns>
protected override Size ArrangeOverride(Size arrangeSize)
{
this.VerifyScrollData(arrangeSize, _Extent);
if (this.Children == null || this.Children.Count == 0)
{
return arrangeSize;
}
TranslateTransform trans = null;
var uiElement = Children[0];
var finalRect = new Rect(uiElement.DesiredSize);
// ScrollContentPresenter sets these to 0 - current offset
// We need to set it to zero in order to make the animation work
finalRect.X = 0;
finalRect.Y = 0;
finalRect.Width = Math.Max(finalRect.Width, arrangeSize.Width);
finalRect.Height = Math.Max(finalRect.Height, arrangeSize.Height);
trans = uiElement.RenderTransform as TranslateTransform;
if (trans == null)
{
uiElement.RenderTransformOrigin = new Point(0, 0);
trans = new TranslateTransform();
uiElement.RenderTransform = trans;
}
uiElement.Arrange(finalRect);
trans.BeginAnimation(TranslateTransform.XProperty,
GetAnimation(0 - HorizontalOffset),
HandoffBehavior.Compose);
trans.BeginAnimation(TranslateTransform.YProperty,
GetAnimation(0 - VerticalOffset),
HandoffBehavior.Compose);
return arrangeSize;
}
/// <summary>
/// Gets the animation.
/// </summary>
/// <param name="toValue">To value.</param>
/// <returns>DoubleAnimation.</returns>
private DoubleAnimation GetAnimation(double toValue)
{
var animation = new DoubleAnimation(toValue, _AnimationLength);
animation.EasingFunction = new ExponentialEase { EasingMode = EasingMode.EaseInOut };
return animation;
}
#region Movement Methods
/// <summary>
/// Scrolls down within content by one logical unit.
/// </summary>
public void LineDown()
{ SetVerticalOffset(VerticalOffset + LineSize); }
/// <summary>
/// Scrolls up within content by one logical unit.
/// </summary>
public void LineUp()
{ SetVerticalOffset(VerticalOffset - LineSize); }
/// <summary>
/// Scrolls left within content by one logical unit.
/// </summary>
public void LineLeft()
{ SetHorizontalOffset(HorizontalOffset - LineSize); }
/// <summary>
/// Scrolls right within content by one logical unit.
/// </summary>
public void LineRight()
{ SetHorizontalOffset(HorizontalOffset + LineSize); }
/// <summary>
/// Scrolls down within content after a user clicks the wheel button on a mouse.
/// </summary>
public void MouseWheelDown()
{ SetVerticalOffset(VerticalOffset + WheelSize); }
/// <summary>
/// Scrolls up within content after a user clicks the wheel button on a mouse.
/// </summary>
public void MouseWheelUp()
{ SetVerticalOffset(VerticalOffset - WheelSize); }
/// <summary>
/// Scrolls left within content after a user clicks the wheel button on a mouse.
/// </summary>
public void MouseWheelLeft()
{ SetHorizontalOffset(HorizontalOffset - WheelSize); }
/// <summary>
/// Scrolls right within content after a user clicks the wheel button on a mouse.
/// </summary>
public void MouseWheelRight()
{ SetHorizontalOffset(HorizontalOffset + WheelSize); }
/// <summary>
/// Scrolls down within content by one page.
/// </summary>
public void PageDown()
{ SetVerticalOffset(VerticalOffset + ViewportHeight); }
/// <summary>
/// Scrolls up within content by one page.
/// </summary>
public void PageUp()
{ SetVerticalOffset(VerticalOffset - ViewportHeight); }
/// <summary>
/// Scrolls left within content by one page.
/// </summary>
public void PageLeft()
{ SetHorizontalOffset(HorizontalOffset - ViewportWidth); }
/// <summary>
/// Scrolls right within content by one page.
/// </summary>
public void PageRight()
{ SetHorizontalOffset(HorizontalOffset + ViewportWidth); }
#endregion
/// <summary>
/// Gets or sets a <see cref="T:System.Windows.Controls.ScrollViewer" /> element that controls scrolling behavior.
/// </summary>
/// <value>The scroll owner.</value>
/// <returns>A <see cref="T:System.Windows.Controls.ScrollViewer" /> element that controls scrolling behavior. This property has no default value.</returns>
public ScrollViewer ScrollOwner { get; set; }
/// <summary>
/// Gets or sets a value that indicates whether scrolling on the horizontal axis is possible.
/// </summary>
/// <value><c>true</c> if this instance can horizontally scroll; otherwise, <c>false</c>.</value>
/// <returns>true if scrolling is possible; otherwise, false. This property has no default value.</returns>
public bool CanHorizontallyScroll { get; set; }
/// <summary>
/// Gets or sets a value that indicates whether scrolling on the vertical axis is possible.
/// </summary>
/// <value><c>true</c> if this instance can vertically scroll; otherwise, <c>false</c>.</value>
/// <returns>true if scrolling is possible; otherwise, false. This property has no default value.</returns>
public bool CanVerticallyScroll { get; set; }
/// <summary>
/// Gets the vertical size of the extent.
/// </summary>
/// <value>The height of the extent.</value>
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the vertical size of the extent.This property has no default value.</returns>
public double ExtentHeight
{ get { return _Extent.Height; } }
/// <summary>
/// Gets the horizontal size of the extent.
/// </summary>
/// <value>The width of the extent.</value>
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the horizontal size of the extent. This property has no default value.</returns>
public double ExtentWidth
{ get { return _Extent.Width; } }
/// <summary>
/// Gets the horizontal offset of the scrolled content.
/// </summary>
/// <value>The horizontal offset.</value>
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the horizontal offset. This property has no default value.</returns>
public double HorizontalOffset
{ get { return _Offset.X; } }
/// <summary>
/// Gets the vertical offset of the scrolled content.
/// </summary>
/// <value>The vertical offset.</value>
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the vertical offset of the scrolled content. Valid values are between zero and the <see cref="P:System.Windows.Controls.Primitives.IScrollInfo.ExtentHeight" /> minus the <see cref="P:System.Windows.Controls.Primitives.IScrollInfo.ViewportHeight" />. This property has no default value.</returns>
public double VerticalOffset
{ get { return _Offset.Y; } }
/// <summary>
/// Gets the vertical size of the viewport for this content.
/// </summary>
/// <value>The height of the viewport.</value>
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the vertical size of the viewport for this content. This property has no default value.</returns>
public double ViewportHeight
{ get { return _Viewport.Height; } }
/// <summary>
/// Gets the horizontal size of the viewport for this content.
/// </summary>
/// <value>The width of the viewport.</value>
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the horizontal size of the viewport for this content. This property has no default value.</returns>
public double ViewportWidth
{ get { return _Viewport.Width; } }
/// <summary>
/// Forces content to scroll until the coordinate space of a <see cref="T:System.Windows.Media.Visual" /> object is visible.
/// </summary>
/// <param name="visual">A <see cref="T:System.Windows.Media.Visual" /> that becomes visible.</param>
/// <param name="rectangle">A bounding rectangle that identifies the coordinate space to make visible.</param>
/// <returns>A <see cref="T:System.Windows.Rect" /> that is visible.</returns>
public Rect MakeVisible(Visual visual, Rect rectangle)
{
if (rectangle.IsEmpty || visual == null
|| visual == this || !base.IsAncestorOf(visual))
{ return Rect.Empty; }
rectangle = visual.TransformToAncestor(this).TransformBounds(rectangle);
//rectangle.Inflate(50, 50);
rectangle.Scale(1.2, 1.2);
Rect viewRect = new Rect(HorizontalOffset,
VerticalOffset, ViewportWidth, ViewportHeight);
rectangle.X += viewRect.X;
rectangle.Y += viewRect.Y;
viewRect.X = CalculateNewScrollOffset(viewRect.Left,
viewRect.Right, rectangle.Left, rectangle.Right);
viewRect.Y = CalculateNewScrollOffset(viewRect.Top,
viewRect.Bottom, rectangle.Top, rectangle.Bottom);
SetHorizontalOffset(viewRect.X);
SetVerticalOffset(viewRect.Y);
rectangle.Intersect(viewRect);
rectangle.X -= viewRect.X;
rectangle.Y -= viewRect.Y;
return rectangle;
}
/// <summary>
/// Calculates the new scroll offset.
/// </summary>
/// <param name="topView">The top view.</param>
/// <param name="bottomView">The bottom view.</param>
/// <param name="topChild">The top child.</param>
/// <param name="bottomChild">The bottom child.</param>
/// <returns>System.Double.</returns>
private static double CalculateNewScrollOffset(double topView,
double bottomView, double topChild, double bottomChild)
{
bool offBottom = topChild < topView && bottomChild < bottomView;
bool offTop = bottomChild > bottomView && topChild > topView;
bool tooLarge = (bottomChild - topChild) > (bottomView - topView);
if (!offBottom && !offTop)
{ return topView; } //Don't do anything, already in view
if ((offBottom && !tooLarge) || (offTop && tooLarge))
{ return topChild; }
return (bottomChild - (bottomView - topView));
}
/// <summary>
/// Verifies the scroll data.
/// </summary>
/// <param name="viewport">The viewport.</param>
/// <param name="extent">The extent.</param>
protected void VerifyScrollData(Size viewport, Size extent)
{
if (double.IsInfinity(viewport.Width))
{ viewport.Width = extent.Width; }
if (double.IsInfinity(viewport.Height))
{ viewport.Height = extent.Height; }
_Extent = extent;
_Viewport = viewport;
_Offset.X = Math.Max(0,
Math.Min(_Offset.X, ExtentWidth - ViewportWidth));
_Offset.Y = Math.Max(0,
Math.Min(_Offset.Y, ExtentHeight - ViewportHeight));
if (ScrollOwner != null)
{ ScrollOwner.InvalidateScrollInfo(); }
}
/// <summary>
/// Sets the amount of horizontal offset.
/// </summary>
/// <param name="offset">The degree to which content is horizontally offset from the containing viewport.</param>
public void SetHorizontalOffset(double offset)
{
offset = Math.Max(0,
Math.Min(offset, ExtentWidth - ViewportWidth));
if (!offset.Equals(_Offset.X))
{
_Offset.X = offset;
InvalidateArrange();
}
}
/// <summary>
/// Sets the amount of vertical offset.
/// </summary>
/// <param name="offset">The degree to which content is vertically offset from the containing viewport.</param>
public void SetVerticalOffset(double offset)
{
offset = Math.Max(0,
Math.Min(offset, ExtentHeight - ViewportHeight));
if (!offset.Equals(_Offset.Y))
{
_Offset.Y = offset;
InvalidateArrange();
}
}
}
}

View File

@@ -0,0 +1,17 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MediaBrowser.UI.Controls">
<Style TargetType="local:TransitionControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:TransitionControl">
<Grid>
<ContentPresenter x:Name="ContentPresenter" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,147 @@
using Microsoft.Expression.Media.Effects;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// http://victorcher.blogspot.com/2012/02/wpf-transactions.html
/// </summary>
public class TransitionControl : ContentControl
{
/// <summary>
/// The _content presenter
/// </summary>
private ContentPresenter _contentPresenter;
/// <summary>
/// Initializes static members of the <see cref="TransitionControl" /> class.
/// </summary>
static TransitionControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(TransitionControl), new FrameworkPropertyMetadata(typeof(TransitionControl)));
ContentProperty.OverrideMetadata(
typeof(TransitionControl), new FrameworkPropertyMetadata(OnContentPropertyChanged));
}
/// <summary>
/// When overridden in a derived class, is invoked whenever application code or internal processes call <see cref="M:System.Windows.FrameworkElement.ApplyTemplate" />.
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_contentPresenter = (ContentPresenter)Template.FindName("ContentPresenter", this);
}
#region DP TransitionType
/// <summary>
/// Gets or sets the type of the transition.
/// </summary>
/// <value>The type of the transition.</value>
public TransitionEffect TransitionType
{
get { return (TransitionEffect)GetValue(TransitionTypeProperty); }
set { SetValue(TransitionTypeProperty, value); }
}
// Using a DependencyProperty as the backing store for TransitionType. This enables animation, styling, binding, etc...
/// <summary>
/// The transition type property
/// </summary>
public static readonly DependencyProperty TransitionTypeProperty =
DependencyProperty.Register("TransitionType", typeof(TransitionEffect), typeof(TransitionControl),
new UIPropertyMetadata(new BlindsTransitionEffect()));
#endregion DP TransitionType
#region DP Transition Animation
/// <summary>
/// Gets or sets the transition animation.
/// </summary>
/// <value>The transition animation.</value>
public DoubleAnimation TransitionAnimation
{
get { return (DoubleAnimation)GetValue(TransitionAnimationProperty); }
set { SetValue(TransitionAnimationProperty, value); }
}
// Using a DependencyProperty as the backing store for TransitionAnimation. This enables animation, styling, binding, etc...
/// <summary>
/// The transition animation property
/// </summary>
public static readonly DependencyProperty TransitionAnimationProperty =
DependencyProperty.Register("TransitionAnimation", typeof(DoubleAnimation), typeof(TransitionControl), new UIPropertyMetadata(null));
#endregion DP Transition Animation
/// <summary>
/// Called when [content property changed].
/// </summary>
/// <param name="dp">The dp.</param>
/// <param name="args">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param>
private static void OnContentPropertyChanged(DependencyObject dp, DependencyPropertyChangedEventArgs args)
{
var oldContent = args.OldValue;
var newContent = args.NewValue;
var transitionControl = (TransitionControl)dp;
if (DesignerProperties.GetIsInDesignMode(transitionControl))
return;
if (oldContent != null && newContent != null && transitionControl.IsVisible)
{
transitionControl.AnimateContent(oldContent, newContent);
}
else if (newContent != null)
{
transitionControl.Content = newContent;
}
}
/// <summary>
/// Animates the content.
/// </summary>
/// <param name="oldContent">The old content.</param>
/// <param name="newContent">The new content.</param>
private void AnimateContent(object oldContent, object newContent)
{
FrameworkElement oldContentVisual;
try
{
oldContentVisual = VisualTreeHelper.GetChild(_contentPresenter, 0) as FrameworkElement;
}
catch
{
return;
}
var transitionEffect = TransitionType;
if (transitionEffect == null)
{
_contentPresenter.Content = newContent;
return;
}
var da = TransitionAnimation;
da.From = 0;
da.To = 1;
da.FillBehavior = FillBehavior.HoldEnd;
transitionEffect.OldImage = new VisualBrush(oldContentVisual);
transitionEffect.BeginAnimation(TransitionEffect.ProgressProperty, da);
_contentPresenter.Effect = transitionEffect;
_contentPresenter.Content = newContent;
}
}
}

View File

@@ -0,0 +1,194 @@
using Microsoft.Expression.Media.Effects;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// Class TransitionFrame
/// </summary>
public class TransitionFrame : Frame
{
/// <summary>
/// The _content presenter
/// </summary>
private ContentPresenter _contentPresenter = null;
#region DP TransitionType
/// <summary>
/// Gets or sets the type of the transition.
/// </summary>
/// <value>The type of the transition.</value>
public TransitionEffect TransitionType
{
get { return (TransitionEffect)GetValue(TransitionTypeProperty); }
set { SetValue(TransitionTypeProperty, value); }
}
// Using a DependencyProperty as the backing store for TransitionType. This enables animation, styling, binding, etc...
/// <summary>
/// The transition type property
/// </summary>
public static readonly DependencyProperty TransitionTypeProperty =
DependencyProperty.Register("TransitionType", typeof(TransitionEffect), typeof(TransitionFrame),
new UIPropertyMetadata(new BlindsTransitionEffect()));
#endregion DP TransitionType
#region DP Transition Animation
/// <summary>
/// Gets or sets the transition animation.
/// </summary>
/// <value>The transition animation.</value>
public DoubleAnimation TransitionAnimation
{
get { return (DoubleAnimation)GetValue(TransitionAnimationProperty); }
set { SetValue(TransitionAnimationProperty, value); }
}
// Using a DependencyProperty as the backing store for TransitionAnimation. This enables animation, styling, binding, etc...
/// <summary>
/// The transition animation property
/// </summary>
public static readonly DependencyProperty TransitionAnimationProperty =
DependencyProperty.Register("TransitionAnimation", typeof(DoubleAnimation), typeof(TransitionFrame), new UIPropertyMetadata(null));
#endregion DP Transition Animation
/// <summary>
/// Called when the template generation for the visual tree is created.
/// </summary>
public override void OnApplyTemplate()
{
// get a reference to the frame's content presenter
// this is the element we will fade in and out
_contentPresenter = GetTemplateChild("PART_FrameCP") as ContentPresenter;
base.OnApplyTemplate();
}
/// <summary>
/// Animates the content.
/// </summary>
/// <param name="navigationAction">The navigation action.</param>
/// <param name="checkContent">if set to <c>true</c> [check content].</param>
/// <param name="isBack">if set to <c>true</c> [is back].</param>
private void AnimateContent(Action navigationAction, bool checkContent = true, bool isBack = false)
{
if (TransitionType == null || (checkContent && Content == null))
{
CommandBindings.Clear();
navigationAction();
CommandBindings.Clear();
return;
}
var oldContentVisual = this as FrameworkElement;
_contentPresenter.IsHitTestVisible = false;
var da = TransitionAnimation.Clone();
da.From = 0;
da.To = 1;
da.FillBehavior = FillBehavior.HoldEnd;
var transitionEffect = TransitionType.Clone() as TransitionEffect;
if (isBack)
{
ReverseDirection(transitionEffect);
}
transitionEffect.OldImage = new VisualBrush(oldContentVisual);
transitionEffect.BeginAnimation(TransitionEffect.ProgressProperty, da);
_contentPresenter.Effect = transitionEffect;
_contentPresenter.IsHitTestVisible = true;
// Remove base class bindings to remote buttons
CommandBindings.Clear();
navigationAction();
CommandBindings.Clear();
}
/// <summary>
/// Navigates the with transition.
/// </summary>
/// <param name="page">The page.</param>
public void NavigateWithTransition(Page page)
{
AnimateContent(() => Navigate(page));
}
/// <summary>
/// Navigates the with transition.
/// </summary>
/// <param name="page">The page.</param>
public void NavigateWithTransition(Uri page)
{
AnimateContent(() => Navigate(page));
}
/// <summary>
/// Goes the back with transition.
/// </summary>
public void GoBackWithTransition()
{
if (CanGoBack)
{
AnimateContent(GoBack, false, true);
}
}
/// <summary>
/// Goes the forward with transition.
/// </summary>
public void GoForwardWithTransition()
{
if (CanGoForward)
{
AnimateContent(GoForward, false);
}
}
/// <summary>
/// Reverses the direction.
/// </summary>
/// <param name="transitionEffect">The transition effect.</param>
private void ReverseDirection(TransitionEffect transitionEffect)
{
var circleRevealTransitionEffect = transitionEffect as CircleRevealTransitionEffect;
if (circleRevealTransitionEffect != null)
{
circleRevealTransitionEffect.Reverse = true;
return;
}
var slideInTransitionEffect = transitionEffect as SlideInTransitionEffect;
if (slideInTransitionEffect != null)
{
if (slideInTransitionEffect.SlideDirection == SlideDirection.RightToLeft)
{
slideInTransitionEffect.SlideDirection = SlideDirection.LeftToRight;
}
return;
}
var wipeTransitionEffect = transitionEffect as WipeTransitionEffect;
if (wipeTransitionEffect != null)
{
if (wipeTransitionEffect.WipeDirection == WipeDirection.RightToLeft)
{
wipeTransitionEffect.WipeDirection = WipeDirection.LeftToRight;
}
}
}
}
}

View File

@@ -0,0 +1,321 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// Helper methods for UI-related tasks.
/// </summary>
public static class TreeHelper
{
/// <summary>
/// Gets the window.
/// </summary>
/// <param name="element">The element.</param>
/// <returns>Window.</returns>
/// <value>The window.</value>
public static Window GetWindow(this FrameworkElement element)
{
return element.ParentOfType<Window>();
}
/// <summary>
/// Gets the parent.
/// </summary>
/// <param name="element">The element.</param>
/// <returns>DependencyObject.</returns>
private static DependencyObject GetParent(this DependencyObject element)
{
DependencyObject parent = VisualTreeHelper.GetParent(element);
if (parent == null)
{
FrameworkElement frameworkElement = element as FrameworkElement;
if (frameworkElement != null)
{
parent = frameworkElement.Parent;
}
}
return parent;
}
/// <summary>
/// Gets the parents.
/// </summary>
/// <param name="element">The element.</param>
/// <returns>IEnumerable{DependencyObject}.</returns>
/// <exception cref="System.ArgumentNullException">element</exception>
public static IEnumerable<DependencyObject> GetParents(this DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
while ((element = element.GetParent()) != null)
{
yield return element;
}
yield break;
}
/// <summary>
/// Parents the type of the of.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="element">The element.</param>
/// <returns>``0.</returns>
public static T ParentOfType<T>(this DependencyObject element) where T : DependencyObject
{
if (element == null)
{
return default(T);
}
return element.GetParents().OfType<T>().FirstOrDefault<T>();
}
/// <summary>
/// Finds a Child of a given item in the visual tree.
/// </summary>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="parent">A direct parent of the queried item.</param>
/// <param name="childName">x:Name or Name of child.</param>
/// <returns>The first parent item that matches the submitted type parameter.
/// If not matching item can be found,
/// a null parent is being returned.</returns>
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject
{
// Confirm parent and childName are valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
/// <summary>
/// Gets the visual child.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="referenceVisual">The reference visual.</param>
/// <returns>``0.</returns>
public static T GetVisualChild<T>(this Visual referenceVisual) where T : Visual
{
Visual child = null;
for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceVisual); i++)
{
child = VisualTreeHelper.GetChild(referenceVisual, i) as Visual;
if (child != null && (child.GetType() == typeof(T)))
{
break;
}
else if (child != null)
{
child = GetVisualChild<T>(child);
if (child != null && (child.GetType() == typeof(T)))
{
break;
}
}
}
return child as T;
}
#region find parent
/// <summary>
/// Finds a parent of a given item on the visual tree.
/// </summary>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="child">A direct or indirect child of the
/// queried item.</param>
/// <returns>The first parent item that matches the submitted
/// type parameter. If not matching item can be found, a null
/// reference is being returned.</returns>
public static T TryFindParent<T>(this DependencyObject child)
where T : DependencyObject
{
//get parent item
DependencyObject parentObject = GetParentObject(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
{
return parent;
}
//use recursion to proceed with next level
return TryFindParent<T>(parentObject);
}
/// <summary>
/// This method is an alternative to WPF's
/// <see cref="VisualTreeHelper.GetParent" /> method, which also
/// supports content elements. Keep in mind that for content element,
/// this method falls back to the logical tree of the element!
/// </summary>
/// <param name="child">The item to be processed.</param>
/// <returns>The submitted item's parent, if available. Otherwise
/// null.</returns>
public static DependencyObject GetParentObject(this DependencyObject child)
{
if (child == null) return null;
//handle content elements separately
ContentElement contentElement = child as ContentElement;
if (contentElement != null)
{
DependencyObject parent = ContentOperations.GetParent(contentElement);
if (parent != null) return parent;
FrameworkContentElement fce = contentElement as FrameworkContentElement;
return fce != null ? fce.Parent : null;
}
//also try searching for parent in framework elements (such as DockPanel, etc)
FrameworkElement frameworkElement = child as FrameworkElement;
if (frameworkElement != null)
{
DependencyObject parent = frameworkElement.Parent;
if (parent != null) return parent;
}
//if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper
return VisualTreeHelper.GetParent(child);
}
#endregion
#region find children
/// <summary>
/// Analyzes both visual and logical tree in order to find all elements of a given
/// type that are descendants of the <paramref name="source" /> item.
/// </summary>
/// <typeparam name="T">The type of the queried items.</typeparam>
/// <param name="source">The root element that marks the source of the search. If the
/// source is already of the requested type, it will not be included in the result.</param>
/// <returns>All descendants of <paramref name="source" /> that match the requested type.</returns>
public static IEnumerable<T> FindChildren<T>(this DependencyObject source) where T : DependencyObject
{
if (source != null)
{
var childs = GetChildObjects(source);
foreach (DependencyObject child in childs)
{
//analyze if children match the requested type
if (child is T)
{
yield return (T)child;
}
//recurse tree
foreach (T descendant in FindChildren<T>(child))
{
yield return descendant;
}
}
}
}
/// <summary>
/// This method is an alternative to WPF's
/// <see cref="VisualTreeHelper.GetChild" /> method, which also
/// supports content elements. Keep in mind that for content elements,
/// this method falls back to the logical tree of the element.
/// </summary>
/// <param name="parent">The item to be processed.</param>
/// <returns>The submitted item's child elements, if available.</returns>
public static IEnumerable<DependencyObject> GetChildObjects(this DependencyObject parent)
{
if (parent == null) yield break;
if (parent is ContentElement || parent is FrameworkElement)
{
//use the logical tree for content / framework elements
foreach (object obj in LogicalTreeHelper.GetChildren(parent))
{
var depObj = obj as DependencyObject;
if (depObj != null) yield return (DependencyObject)obj;
}
}
else
{
//use the visual tree per default
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
yield return VisualTreeHelper.GetChild(parent, i);
}
}
}
#endregion
#region find from point
/// <summary>
/// Tries to locate a given item within the visual tree,
/// starting with the dependency object at a given position.
/// </summary>
/// <typeparam name="T">The type of the element to be found
/// on the visual tree of the element at the given location.</typeparam>
/// <param name="reference">The main element which is used to perform
/// hit testing.</param>
/// <param name="point">The position to be evaluated on the origin.</param>
/// <returns>``0.</returns>
public static T TryFindFromPoint<T>(UIElement reference, Point point)
where T : DependencyObject
{
DependencyObject element = reference.InputHitTest(point) as DependencyObject;
if (element == null) return null;
if (element is T) return (T)element;
return TryFindParent<T>(element);
}
#endregion
}
}

View File

@@ -0,0 +1,735 @@
using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace MediaBrowser.UI.Controls
{
/// <summary>
/// http://www.codeproject.com/Articles/75847/Virtualizing-WrapPanel
/// Positions child elements in sequential position from left to right, breaking content
/// to the next line at the edge of the containing box. Subsequent ordering happens
/// sequentially from top to bottom or from right to left, depending on the value of
/// the Orientation property.
/// </summary>
[DefaultProperty("Orientation")]
public class VirtualizingWrapPanel : VirtualizingPanel, IScrollInfo
{
/// <summary>
/// Identifies the ItemHeight dependency property.
/// </summary>
public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register("ItemHeight", typeof(double), typeof(VirtualizingWrapPanel), new PropertyMetadata(100.0, new PropertyChangedCallback(VirtualizingWrapPanel.OnAppearancePropertyChanged)));
/// <summary>
/// Identifies the Orientation dependency property.
/// </summary>
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(VirtualizingWrapPanel), new PropertyMetadata(Orientation.Horizontal, new PropertyChangedCallback(VirtualizingWrapPanel.OnAppearancePropertyChanged)));
/// <summary>
/// Identifies the ItemWidth dependency property.
/// </summary>
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register("ItemWidth", typeof(double), typeof(VirtualizingWrapPanel), new PropertyMetadata(100.0, new PropertyChangedCallback(VirtualizingWrapPanel.OnAppearancePropertyChanged)));
/// <summary>
/// Identifies the ScrollStep dependency property.
/// </summary>
public static readonly DependencyProperty ScrollStepProperty = DependencyProperty.Register("ScrollStep", typeof(double), typeof(VirtualizingWrapPanel), new PropertyMetadata(10.0, new PropertyChangedCallback(VirtualizingWrapPanel.OnAppearancePropertyChanged)));
private bool canHorizontallyScroll;
private bool canVerticallyScroll;
private Size contentExtent = new Size(0.0, 0.0);
private Point contentOffset = default(Point);
private ScrollViewer scrollOwner;
private Size viewport = new Size(0.0, 0.0);
private int previousItemCount;
/// <summary>
/// Gets or sets a value that specifies the height of all items that are
/// contained within a VirtualizingWrapPanel. This is a dependency property.
/// </summary>
public double ItemHeight
{
get
{
return (double)base.GetValue(VirtualizingWrapPanel.ItemHeightProperty);
}
set
{
base.SetValue(VirtualizingWrapPanel.ItemHeightProperty, value);
}
}
/// <summary>
/// Gets or sets a value that specifies the width of all items that are
/// contained within a VirtualizingWrapPanel. This is a dependency property.
/// </summary>
public double ItemWidth
{
get
{
return (double)base.GetValue(VirtualizingWrapPanel.ItemWidthProperty);
}
set
{
base.SetValue(VirtualizingWrapPanel.ItemWidthProperty, value);
}
}
/// <summary>
/// Gets or sets a value that specifies the dimension in which child
/// content is arranged. This is a dependency property.
/// </summary>
public Orientation Orientation
{
get
{
return (Orientation)base.GetValue(VirtualizingWrapPanel.OrientationProperty);
}
set
{
base.SetValue(VirtualizingWrapPanel.OrientationProperty, value);
}
}
/// <summary>
/// Gets or sets a value that indicates whether scrolling on the horizontal axis is possible.
/// </summary>
public bool CanHorizontallyScroll
{
get
{
return this.canHorizontallyScroll;
}
set
{
if (this.canHorizontallyScroll != value)
{
this.canHorizontallyScroll = value;
base.InvalidateMeasure();
}
}
}
/// <summary>
/// Gets or sets a value that indicates whether scrolling on the vertical axis is possible.
/// </summary>
public bool CanVerticallyScroll
{
get
{
return this.canVerticallyScroll;
}
set
{
if (this.canVerticallyScroll != value)
{
this.canVerticallyScroll = value;
base.InvalidateMeasure();
}
}
}
/// <summary>
/// Gets or sets a ScrollViewer element that controls scrolling behavior.
/// </summary>
public ScrollViewer ScrollOwner
{
get
{
return this.scrollOwner;
}
set
{
this.scrollOwner = value;
}
}
/// <summary>
/// Gets the vertical offset of the scrolled content.
/// </summary>
public double VerticalOffset
{
get
{
return this.contentOffset.Y;
}
}
/// <summary>
/// Gets the vertical size of the viewport for this content.
/// </summary>
public double ViewportHeight
{
get
{
return this.viewport.Height;
}
}
/// <summary>
/// Gets the horizontal size of the viewport for this content.
/// </summary>
public double ViewportWidth
{
get
{
return this.viewport.Width;
}
}
/// <summary>
/// Gets or sets a value for mouse wheel scroll step.
/// </summary>
public double ScrollStep
{
get
{
return (double)base.GetValue(VirtualizingWrapPanel.ScrollStepProperty);
}
set
{
base.SetValue(VirtualizingWrapPanel.ScrollStepProperty, value);
}
}
/// <summary>
/// Gets the vertical size of the extent.
/// </summary>
public double ExtentHeight
{
get
{
return this.contentExtent.Height;
}
}
/// <summary>
/// Gets the horizontal size of the extent.
/// </summary>
public double ExtentWidth
{
get
{
return this.contentExtent.Width;
}
}
/// <summary>
/// Gets the horizontal offset of the scrolled content.
/// </summary>
public double HorizontalOffset
{
get
{
return this.contentOffset.X;
}
}
/// <summary>
/// Scrolls down within content by one logical unit.
/// </summary>
public void LineDown()
{
this.SetVerticalOffset(this.VerticalOffset + this.ScrollStep);
}
/// <summary>
/// Scrolls left within content by one logical unit.
/// </summary>
public void LineLeft()
{
this.SetHorizontalOffset(this.HorizontalOffset - this.ScrollStep);
}
/// <summary>
/// Scrolls right within content by one logical unit.
/// </summary>
public void LineRight()
{
this.SetHorizontalOffset(this.HorizontalOffset + this.ScrollStep);
}
/// <summary>
/// Scrolls up within content by one logical unit.
/// </summary>
public void LineUp()
{
this.SetVerticalOffset(this.VerticalOffset - this.ScrollStep);
}
/// <summary>
/// Forces content to scroll until the coordinate space of a Visual object is visible.
/// </summary>
public Rect MakeVisible(Visual visual, Rect rectangle)
{
this.MakeVisible(visual as UIElement);
return rectangle;
}
/// <summary>
/// Scrolls down within content after a user clicks the wheel button on a mouse.
/// </summary>
public void MouseWheelDown()
{
this.SetVerticalOffset(this.VerticalOffset + this.ScrollStep);
}
/// <summary>
/// Scrolls left within content after a user clicks the wheel button on a mouse.
/// </summary>
public void MouseWheelLeft()
{
this.SetHorizontalOffset(this.HorizontalOffset - this.ScrollStep);
}
/// <summary>
/// Scrolls right within content after a user clicks the wheel button on a mouse.
/// </summary>
public void MouseWheelRight()
{
this.SetHorizontalOffset(this.HorizontalOffset + this.ScrollStep);
}
/// <summary>
/// Scrolls up within content after a user clicks the wheel button on a mouse.
/// </summary>
public void MouseWheelUp()
{
this.SetVerticalOffset(this.VerticalOffset - this.ScrollStep);
}
/// <summary>
/// Scrolls down within content by one page.
/// </summary>
public void PageDown()
{
this.SetVerticalOffset(this.VerticalOffset + this.ViewportHeight);
}
/// <summary>
/// Scrolls left within content by one page.
/// </summary>
public void PageLeft()
{
this.SetHorizontalOffset(this.HorizontalOffset - this.ViewportHeight);
}
/// <summary>
/// Scrolls right within content by one page.
/// </summary>
public void PageRight()
{
this.SetHorizontalOffset(this.HorizontalOffset + this.ViewportHeight);
}
/// <summary>
/// Scrolls up within content by one page.
/// </summary>
public void PageUp()
{
this.SetVerticalOffset(this.VerticalOffset - this.viewport.Height);
}
/// <summary>
/// Sets the amount of vertical offset.
/// </summary>
public void SetVerticalOffset(double offset)
{
if (offset < 0.0 || this.ViewportHeight >= this.ExtentHeight)
{
offset = 0.0;
}
else
{
if (offset + this.ViewportHeight >= this.ExtentHeight)
{
offset = this.ExtentHeight - this.ViewportHeight;
}
}
this.contentOffset.Y = offset;
if (this.ScrollOwner != null)
{
this.ScrollOwner.InvalidateScrollInfo();
}
base.InvalidateMeasure();
}
/// <summary>
/// Sets the amount of horizontal offset.
/// </summary>
public void SetHorizontalOffset(double offset)
{
if (offset < 0.0 || this.ViewportWidth >= this.ExtentWidth)
{
offset = 0.0;
}
else
{
if (offset + this.ViewportWidth >= this.ExtentWidth)
{
offset = this.ExtentWidth - this.ViewportWidth;
}
}
this.contentOffset.X = offset;
if (this.ScrollOwner != null)
{
this.ScrollOwner.InvalidateScrollInfo();
}
base.InvalidateMeasure();
}
/// <summary>
/// Note: Works only for vertical.
/// </summary>
internal void PageLast()
{
this.contentOffset.Y = this.ExtentHeight;
if (this.ScrollOwner != null)
{
this.ScrollOwner.InvalidateScrollInfo();
}
base.InvalidateMeasure();
}
/// <summary>
/// Note: Works only for vertical.
/// </summary>
internal void PageFirst()
{
this.contentOffset.Y = 0.0;
if (this.ScrollOwner != null)
{
this.ScrollOwner.InvalidateScrollInfo();
}
base.InvalidateMeasure();
}
/// <summary>
/// When items are removed, remove the corresponding UI if necessary.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args)
{
switch (args.Action)
{
case NotifyCollectionChangedAction.Remove:
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Move:
base.RemoveInternalChildRange(args.Position.Index, args.ItemUICount);
return;
case NotifyCollectionChangedAction.Reset:
{
ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);
if (itemsControl != null)
{
if (this.previousItemCount != itemsControl.Items.Count)
{
if (this.Orientation == Orientation.Horizontal)
{
this.SetVerticalOffset(0.0);
}
else
{
this.SetHorizontalOffset(0.0);
}
}
this.previousItemCount = itemsControl.Items.Count;
}
return;
}
default:
return;
}
}
/// <summary>
/// Measure the children.
/// </summary>
/// <param name="availableSize">The available size.</param>
/// <returns>The desired size.</returns>
protected override Size MeasureOverride(Size availableSize)
{
this.InvalidateScrollInfo(availableSize);
int firstVisibleIndex;
int lastVisibleIndex;
if (this.Orientation == Orientation.Horizontal)
{
this.GetVerticalVisibleRange(out firstVisibleIndex, out lastVisibleIndex);
}
else
{
this.GetHorizontalVisibleRange(out firstVisibleIndex, out lastVisibleIndex);
}
UIElementCollection children = base.Children;
IItemContainerGenerator generator = base.ItemContainerGenerator;
if (generator != null)
{
GeneratorPosition startPos = generator.GeneratorPositionFromIndex(firstVisibleIndex);
int childIndex = (startPos.Offset == 0) ? startPos.Index : (startPos.Index + 1);
if (childIndex == -1)
{
this.RefreshOffset();
}
using (generator.StartAt(startPos, GeneratorDirection.Forward, true))
{
int itemIndex = firstVisibleIndex;
while (itemIndex <= lastVisibleIndex)
{
bool newlyRealized;
UIElement child = generator.GenerateNext(out newlyRealized) as UIElement;
if (newlyRealized)
{
if (childIndex >= children.Count)
{
base.AddInternalChild(child);
}
else
{
base.InsertInternalChild(childIndex, child);
}
generator.PrepareItemContainer(child);
}
if (child != null)
{
child.Measure(new Size(this.ItemWidth, this.ItemHeight));
}
itemIndex++;
childIndex++;
}
}
this.CleanUpChildren(firstVisibleIndex, lastVisibleIndex);
}
if (IsCloseTo(availableSize.Height, double.PositiveInfinity) || IsCloseTo(availableSize.Width, double.PositiveInfinity))
{
return base.MeasureOverride(availableSize);
}
var itemsControl = ItemsControl.GetItemsOwner(this);
var numItems = itemsControl.Items.Count;
var width = availableSize.Width;
var height = availableSize.Height;
if (Orientation == Orientation.Vertical)
{
var numRows = Math.Floor(availableSize.Height / ItemHeight);
height = numRows * ItemHeight;
var requiredColumns = Math.Ceiling(numItems / numRows);
width = Math.Min(requiredColumns * ItemWidth, width);
}
else
{
var numColumns = Math.Floor(availableSize.Width / ItemWidth);
width = numColumns * ItemWidth;
//if (numItems > 0 && numItems < numColumns)
//{
// width = Math.Min(numColumns, numItems) * ItemWidth;
//}
var requiredRows = Math.Ceiling(numItems / numColumns);
height = Math.Min(requiredRows * ItemHeight, height);
}
return new Size(width, height);
}
/// <summary>
/// Arranges the children.
/// </summary>
/// <param name="finalSize">The available size.</param>
/// <returns>The used size.</returns>
protected override Size ArrangeOverride(Size finalSize)
{
bool isHorizontal = this.Orientation == Orientation.Horizontal;
this.InvalidateScrollInfo(finalSize);
int i = 0;
foreach (object item in base.Children)
{
this.ArrangeChild(isHorizontal, finalSize, i++, item as UIElement);
}
return finalSize;
}
private static void OnAppearancePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement panel = d as UIElement;
if (panel != null)
{
panel.InvalidateMeasure();
}
}
private void MakeVisible(UIElement element)
{
ItemContainerGenerator generator = base.ItemContainerGenerator.GetItemContainerGeneratorForPanel(this);
if (element != null && generator != null)
{
for (int itemIndex = generator.IndexFromContainer(element); itemIndex == -1; itemIndex = generator.IndexFromContainer(element))
{
element = element.ParentOfType<UIElement>();
}
ScrollViewer scrollViewer = element.ParentOfType<ScrollViewer>();
if (scrollViewer != null)
{
GeneralTransform elementTransform = element.TransformToVisual(scrollViewer);
Rect elementRectangle = elementTransform.TransformBounds(new Rect(new Point(0.0, 0.0), element.RenderSize));
if (this.Orientation == Orientation.Horizontal)
{
var padding = ItemHeight / 3;
if (elementRectangle.Bottom > this.ViewportHeight)
{
this.SetVerticalOffset(this.contentOffset.Y + elementRectangle.Bottom - this.ViewportHeight + padding);
return;
}
if (elementRectangle.Top < 0.0)
{
this.SetVerticalOffset(this.contentOffset.Y + elementRectangle.Top - padding);
return;
}
}
else
{
var padding = ItemWidth / 3;
if (elementRectangle.Right > this.ViewportWidth)
{
this.SetHorizontalOffset(this.contentOffset.X + elementRectangle.Right - this.ViewportWidth + padding);
return;
}
if (elementRectangle.Left < 0.0)
{
this.SetHorizontalOffset(this.contentOffset.X + elementRectangle.Left - padding);
}
}
}
}
}
private void GetVerticalVisibleRange(out int firstVisibleItemIndex, out int lastVisibleItemIndex)
{
int childrenPerRow = this.GetVerticalChildrenCountPerRow(this.contentExtent);
firstVisibleItemIndex = (int)Math.Floor(this.VerticalOffset / this.ItemHeight) * childrenPerRow;
lastVisibleItemIndex = (int)Math.Ceiling((this.VerticalOffset + this.ViewportHeight) / this.ItemHeight) * childrenPerRow - 1;
this.AdjustVisibleRange(ref firstVisibleItemIndex, ref lastVisibleItemIndex);
}
private void GetHorizontalVisibleRange(out int firstVisibleItemIndex, out int lastVisibleItemIndex)
{
int childrenPerRow = this.GetHorizontalChildrenCountPerRow(this.contentExtent);
firstVisibleItemIndex = (int)Math.Floor(this.HorizontalOffset / this.ItemWidth) * childrenPerRow;
lastVisibleItemIndex = (int)Math.Ceiling((this.HorizontalOffset + this.ViewportWidth) / this.ItemWidth) * childrenPerRow - 1;
this.AdjustVisibleRange(ref firstVisibleItemIndex, ref lastVisibleItemIndex);
}
private void AdjustVisibleRange(ref int firstVisibleItemIndex, ref int lastVisibleItemIndex)
{
firstVisibleItemIndex--;
lastVisibleItemIndex++;
ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);
if (itemsControl != null)
{
if (firstVisibleItemIndex < 0)
{
firstVisibleItemIndex = 0;
}
if (lastVisibleItemIndex >= itemsControl.Items.Count)
{
lastVisibleItemIndex = itemsControl.Items.Count - 1;
}
}
}
private void CleanUpChildren(int minIndex, int maxIndex)
{
UIElementCollection children = base.Children;
IItemContainerGenerator generator = base.ItemContainerGenerator;
for (int i = children.Count - 1; i >= 0; i--)
{
GeneratorPosition pos = new GeneratorPosition(i, 0);
int itemIndex = generator.IndexFromGeneratorPosition(pos);
if (itemIndex < minIndex || itemIndex > maxIndex)
{
generator.Remove(pos, 1);
base.RemoveInternalChildRange(i, 1);
}
}
}
private void ArrangeChild(bool isHorizontal, Size finalSize, int index, UIElement child)
{
if (child == null)
{
return;
}
int count = isHorizontal ? this.GetVerticalChildrenCountPerRow(finalSize) : this.GetHorizontalChildrenCountPerRow(finalSize);
int itemIndex = base.ItemContainerGenerator.IndexFromGeneratorPosition(new GeneratorPosition(index, 0));
int row = isHorizontal ? (itemIndex / count) : (itemIndex % count);
int column = isHorizontal ? (itemIndex % count) : (itemIndex / count);
Rect rect = new Rect((double)column * this.ItemWidth, (double)row * this.ItemHeight, this.ItemWidth, this.ItemHeight);
if (isHorizontal)
{
rect.Y -= this.VerticalOffset;
}
else
{
rect.X -= this.HorizontalOffset;
}
child.Arrange(rect);
}
private void InvalidateScrollInfo(Size availableSize)
{
ItemsControl ownerItemsControl = ItemsControl.GetItemsOwner(this);
if (ownerItemsControl != null)
{
Size extent = this.GetExtent(availableSize, ownerItemsControl.Items.Count);
if (extent != this.contentExtent)
{
this.contentExtent = extent;
this.RefreshOffset();
}
if (availableSize != this.viewport)
{
this.viewport = availableSize;
this.InvalidateScrollOwner();
}
}
}
private void RefreshOffset()
{
if (this.Orientation == Orientation.Horizontal)
{
this.SetVerticalOffset(this.VerticalOffset);
return;
}
this.SetHorizontalOffset(this.HorizontalOffset);
}
private void InvalidateScrollOwner()
{
if (this.ScrollOwner != null)
{
this.ScrollOwner.InvalidateScrollInfo();
}
}
private Size GetExtent(Size availableSize, int itemCount)
{
if (this.Orientation == Orientation.Horizontal)
{
int childrenPerRow = this.GetVerticalChildrenCountPerRow(availableSize);
return new Size((double)childrenPerRow * this.ItemWidth, this.ItemHeight * Math.Ceiling((double)itemCount / (double)childrenPerRow));
}
int childrenPerRow2 = this.GetHorizontalChildrenCountPerRow(availableSize);
return new Size(this.ItemWidth * Math.Ceiling((double)itemCount / (double)childrenPerRow2), (double)childrenPerRow2 * this.ItemHeight);
}
private int GetVerticalChildrenCountPerRow(Size availableSize)
{
int childrenCountPerRow;
if (availableSize.Width == double.PositiveInfinity)
{
childrenCountPerRow = base.Children.Count;
}
else
{
childrenCountPerRow = Math.Max(1, (int)Math.Floor(availableSize.Width / this.ItemWidth));
}
return childrenCountPerRow;
}
private int GetHorizontalChildrenCountPerRow(Size availableSize)
{
int childrenCountPerRow;
if (availableSize.Height == double.PositiveInfinity)
{
childrenCountPerRow = base.Children.Count;
}
else
{
childrenCountPerRow = Math.Max(1, (int)Math.Floor(availableSize.Height / this.ItemHeight));
}
return childrenCountPerRow;
}
private static bool IsCloseTo(double value1, double value2)
{
return AreClose(value1, value2);
}
private static bool AreClose(double value1, double value2)
{
if (value1 == value2)
{
return true;
}
double num = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * 2.2204460492503131E-16;
double num2 = value1 - value2;
return -num < num2 && num > num2;
}
}
}