Projektdateien hinzufügen.
This commit is contained in:
32
VideoBrowser.Test/Common/ByteFormatProviderTest.cs
Normal file
32
VideoBrowser.Test/Common/ByteFormatProviderTest.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
namespace VideoBrowser.Test.Common
|
||||||
|
{
|
||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="ByteFormatProviderTest" />
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class ByteFormatProviderTest
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The FileSizeFormatProvider_With_String
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void ByteSizeFormatProvider_With_String()
|
||||||
|
{
|
||||||
|
var provider = new ByteFormatProvider();
|
||||||
|
var size = 1000000.0;
|
||||||
|
var formatedSize = string.Format(new ByteFormatProvider(), "{0:fs}", size);
|
||||||
|
formatedSize.Should().Be("976.56 KB");
|
||||||
|
var speed = 1000000000.0;
|
||||||
|
var formatedSpeed = string.Format(new ByteFormatProvider(), "{0:s}", speed);
|
||||||
|
formatedSpeed.Should().Be("953.67 MB/s");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
31
VideoBrowser.Test/Common/ManualTestAttribute.cs
Normal file
31
VideoBrowser.Test/Common/ManualTestAttribute.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
namespace VideoBrowser.Test.Common
|
||||||
|
{
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="ManualTestAttribute" />.
|
||||||
|
/// </summary>
|
||||||
|
public class ManualTestAttribute : TestCategoryBaseAttribute
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ManualTestAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public ManualTestAttribute()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the TestCategories.
|
||||||
|
/// </summary>
|
||||||
|
public override IList<string> TestCategories => new List<string> { "ManualTest" };
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
}
|
||||||
|
}
|
||||||
28
VideoBrowser.Test/Common/PercentageTest.cs
Normal file
28
VideoBrowser.Test/Common/PercentageTest.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
namespace VideoBrowser.Test.Common
|
||||||
|
{
|
||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="PercentageTest" />
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class PercentageTest
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The PercentageTest_Constructor
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void PercentageTest_Constructor()
|
||||||
|
{
|
||||||
|
var percentage = new Percentage(50);
|
||||||
|
percentage.Normalized.Should().Be(0.5);
|
||||||
|
percentage.ToString().Should().Be("50%");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
42
VideoBrowser.Test/Extensions/StringExtensionTest.cs
Normal file
42
VideoBrowser.Test/Extensions/StringExtensionTest.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
namespace VideoBrowser.Test.Extensions
|
||||||
|
{
|
||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="StringExtensionTest" />
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class StringExtensionTest
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ToFormatedByte
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void ToFormatedByte()
|
||||||
|
{
|
||||||
|
var formatedByte = StringExtension.ToFormatedByte(10000);
|
||||||
|
formatedByte.Should().Be("9.77 KB");
|
||||||
|
formatedByte = StringExtension.ToFormatedByte(20000000);
|
||||||
|
formatedByte.Should().Be("19.07 MB");
|
||||||
|
formatedByte = StringExtension.ToFormatedByte(2000000000);
|
||||||
|
formatedByte.Should().Be("1.86 GB");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ToFormatedSpeed()
|
||||||
|
{
|
||||||
|
var formatedSpeed = StringExtension.ToFormatedSpeed(10000);
|
||||||
|
formatedSpeed.Should().Be("9.77 KB/s");
|
||||||
|
formatedSpeed = StringExtension.ToFormatedSpeed(20000000);
|
||||||
|
formatedSpeed.Should().Be("19.07 MB/s");
|
||||||
|
formatedSpeed = StringExtension.ToFormatedSpeed(2000000000);
|
||||||
|
formatedSpeed.Should().Be("1.86 GB/s");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
52
VideoBrowser.Test/Models/OperationModelTest.cs
Normal file
52
VideoBrowser.Test/Models/OperationModelTest.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
namespace VideoBrowser.Test.Models
|
||||||
|
{
|
||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using VideoBrowser.Models;
|
||||||
|
using VideoBrowser.Test.TestHelpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="OperationModelTest" />.
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class OperationModelTest
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Test.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void ContainsTest()
|
||||||
|
{
|
||||||
|
var operation1 = new DummyOperation
|
||||||
|
{
|
||||||
|
Output = "NewVideo1.mp4"
|
||||||
|
};
|
||||||
|
var operation2 = new DummyOperation
|
||||||
|
{
|
||||||
|
Output = "NewVideo2.mp4"
|
||||||
|
};
|
||||||
|
var operation3 = new DummyOperation
|
||||||
|
{
|
||||||
|
Output = "NewVideo1.mp4"
|
||||||
|
};
|
||||||
|
|
||||||
|
var model1 = new OperationModel(operation1);
|
||||||
|
var model2 = new OperationModel(operation2);
|
||||||
|
var model3 = new OperationModel(operation3);
|
||||||
|
var models = new ObservableCollection<OperationModel>
|
||||||
|
{
|
||||||
|
model1,
|
||||||
|
model2
|
||||||
|
};
|
||||||
|
|
||||||
|
models.Contains(model1).Should().BeTrue();
|
||||||
|
models.Contains(model2).Should().BeTrue();
|
||||||
|
models.Contains(model3).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
17
VideoBrowser.Test/Properties/AssemblyInfo.cs
Normal file
17
VideoBrowser.Test/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
[assembly: AssemblyTitle("VideoBrowser.Test")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("VideoBrowser.Test")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
[assembly: Guid("ceb9d499-9f24-42c0-b6ad-165d2abf9b7b")]
|
||||||
|
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("0.1.7.0")]
|
||||||
|
[assembly: AssemblyFileVersion("0.1.7.0")]
|
||||||
39
VideoBrowser.Test/TestHelpers/DummyOperation.cs
Normal file
39
VideoBrowser.Test/TestHelpers/DummyOperation.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
namespace VideoBrowser.Test.TestHelpers
|
||||||
|
{
|
||||||
|
using System.ComponentModel;
|
||||||
|
using VideoBrowser.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="DummyOperation" />.
|
||||||
|
/// </summary>
|
||||||
|
public class DummyOperation : Operation
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The WorkerCompleted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">The e<see cref="RunWorkerCompletedEventArgs"/>.</param>
|
||||||
|
protected override void WorkerCompleted(RunWorkerCompletedEventArgs e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The WorkerDoWork.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">The e<see cref="DoWorkEventArgs"/>.</param>
|
||||||
|
protected override void WorkerDoWork(DoWorkEventArgs e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The WorkerProgressChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">The e<see cref="ProgressChangedEventArgs"/>.</param>
|
||||||
|
protected override void WorkerProgressChanged(ProgressChangedEventArgs e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
47
VideoBrowser.Test/TestHelpers/TestHelper.cs
Normal file
47
VideoBrowser.Test/TestHelpers/TestHelper.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
namespace VideoBrowser.Test.TestHelpers
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="TestHelper" />.
|
||||||
|
/// </summary>
|
||||||
|
internal static class TestHelper
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Random.
|
||||||
|
/// </summary>
|
||||||
|
private static Random Random { get; } = new Random();
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetRandomInt.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">The start<see cref="int"/>.</param>
|
||||||
|
/// <param name="end">The end<see cref="int"/>.</param>
|
||||||
|
/// <returns>The <see cref="long"/>.</returns>
|
||||||
|
internal static int GetRandomInt(int start, int end)
|
||||||
|
{
|
||||||
|
var random = start + Random.NextDouble() * (end - start);
|
||||||
|
return (int)random;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetRandomLong.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">The start<see cref="long"/>.</param>
|
||||||
|
/// <param name="end">The end<see cref="long"/>.</param>
|
||||||
|
/// <returns>The <see cref="long"/>.</returns>
|
||||||
|
internal static long GetRandomLong(long start, long end)
|
||||||
|
{
|
||||||
|
var random = start + Random.NextDouble() * (end - start);
|
||||||
|
return (long)random;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
24
VideoBrowser.Test/TestHelpers/WindowFactory.cs
Normal file
24
VideoBrowser.Test/TestHelpers/WindowFactory.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
namespace VideoBrowser.Test.TestHelpers
|
||||||
|
{
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="WindowFactory" />.
|
||||||
|
/// </summary>
|
||||||
|
internal static class WindowFactory
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CreateAndShow.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="view">The view<see cref="FrameworkElement"/>.</param>
|
||||||
|
internal static void CreateAndShow(FrameworkElement view)
|
||||||
|
{
|
||||||
|
var window = new Window { Content = view, MinWidth = 600, MinHeight = 400, SizeToContent = SizeToContent.WidthAndHeight };
|
||||||
|
window.ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
111
VideoBrowser.Test/VideoBrowser.Test.csproj
Normal file
111
VideoBrowser.Test/VideoBrowser.Test.csproj
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.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>{CEB9D499-9F24-42C0-B6AD-165D2ABF9B7B}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>VideoBrowser.Test</RootNamespace>
|
||||||
|
<AssemblyName>VideoBrowser.Test</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||||
|
<IsCodedUITest>False</IsCodedUITest>
|
||||||
|
<TestProjectType>UnitTest</TestProjectType>
|
||||||
|
<NuGetPackageImportStamp>
|
||||||
|
</NuGetPackageImportStamp>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</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>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
|
<OutputPath>bin\x64\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<SignAssembly>true</SignAssembly>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FluentAssertions">
|
||||||
|
<HintPath>..\..\..\bin\FluentAssertions.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="PresentationCore" />
|
||||||
|
<Reference Include="PresentationFramework" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Common\ByteFormatProviderTest.cs" />
|
||||||
|
<Compile Include="Common\ManualTestAttribute.cs" />
|
||||||
|
<Compile Include="Common\PercentageTest.cs" />
|
||||||
|
<Compile Include="Models\OperationModelTest.cs" />
|
||||||
|
<Compile Include="TestHelpers\DummyOperation.cs" />
|
||||||
|
<Compile Include="TestHelpers\TestHelper.cs" />
|
||||||
|
<Compile Include="TestHelpers\WindowFactory.cs" />
|
||||||
|
<Compile Include="Extensions\StringExtensionTest.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Views\UrlEditorViewTest.cs" />
|
||||||
|
<Compile Include="Views\SettingsViewTest.cs" />
|
||||||
|
<Compile Include="Views\AboutViewTest.cs" />
|
||||||
|
<Compile Include="Views\DownloadQueueViewTest.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="key.snk" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\VideoBrowser\VideoBrowser.csproj">
|
||||||
|
<Project>{2d8225bc-f5b6-4f29-a9e3-f4694d260597}</Project>
|
||||||
|
<Name>VideoBrowser</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MSTest.TestAdapter">
|
||||||
|
<Version>2.2.7</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="MSTest.TestFramework">
|
||||||
|
<Version>2.2.7</Version> </PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
||||||
30
VideoBrowser.Test/Views/AboutViewTest.cs
Normal file
30
VideoBrowser.Test/Views/AboutViewTest.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
namespace VideoBrowser.Test.Views
|
||||||
|
{
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using VideoBrowser.Test.Common;
|
||||||
|
using VideoBrowser.Test.TestHelpers;
|
||||||
|
using VideoBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Views;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="AboutViewTest" />.
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class AboutViewTest
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Show_AboutView.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod, ManualTest]
|
||||||
|
public void Show_AboutView()
|
||||||
|
{
|
||||||
|
var viewModel = new AboutViewModel();
|
||||||
|
var view = new AboutView { DataContext = viewModel };
|
||||||
|
WindowFactory.CreateAndShow(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
69
VideoBrowser.Test/Views/DownloadQueueViewTest.cs
Normal file
69
VideoBrowser.Test/Views/DownloadQueueViewTest.cs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
namespace VideoBrowser.Test.Views
|
||||||
|
{
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Models;
|
||||||
|
using VideoBrowser.Core;
|
||||||
|
using VideoBrowser.Models;
|
||||||
|
using VideoBrowser.Test.Common;
|
||||||
|
using VideoBrowser.Test.TestHelpers;
|
||||||
|
using VideoBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Views;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="DownloadQueueViewTest" />.
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class DownloadQueueViewTest
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Show_DownloadQueueView.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod, ManualTest]
|
||||||
|
public void Show_DownloadQueueView()
|
||||||
|
{
|
||||||
|
var globalBrowserData = new GlobalBrowserData();
|
||||||
|
var viewModel = new DownloadQueueViewModel(globalBrowserData.DownloadItemModels);
|
||||||
|
this.CreateDummyOperations(viewModel.DownloadItemModels, viewModel.OnPauseDownloadCalled);
|
||||||
|
var view = new DownloadQueueView { DataContext = viewModel };
|
||||||
|
WindowFactory.CreateAndShow(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CreateDummyOperations.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="operations">The operations<see cref="ObservableCollection{OperationModel}"/>.</param>
|
||||||
|
/// <param name="pauseDownloadAction">The pauseDownloadAction<see cref="ICommand"/>.</param>
|
||||||
|
private void CreateDummyOperations(ObservableCollection<DownloadItemModel> operations, Action<DownloadItemModel> pauseDownloadAction)
|
||||||
|
{
|
||||||
|
var random = new Random();
|
||||||
|
for (var i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
var operation = new DummyOperation() { Status = (OperationStatus)(i % 6) };
|
||||||
|
var operationModel = new OperationModel(operation) { PauseDownloadAction = pauseDownloadAction, IsQueuedControlsVisible = (i & 1) == 1 };
|
||||||
|
var progress = TestHelper.GetRandomLong(0, 100);
|
||||||
|
operation.Duration = TestHelper.GetRandomLong(10, 10000);
|
||||||
|
operation.FileSize = TestHelper.GetRandomLong(10000, 10000000000);
|
||||||
|
operation.Input = $"https://youtube.com/view={i}";
|
||||||
|
operation.Link = $"https://youtube.com/link={i}"; ;
|
||||||
|
operation.Output = $@"C:\Users\YoutubeUser\File{TestHelper.GetRandomLong(100, 10000)}.mp4";
|
||||||
|
operation.Progress = progress;
|
||||||
|
operation.ProgressPercentage = (int)progress;
|
||||||
|
operation.ProgressText = $"{progress}%";
|
||||||
|
operation.ReportsProgress = true;
|
||||||
|
operation.Speed = $"{TestHelper.GetRandomInt(10, 100)}MB/s";
|
||||||
|
operation.Status = (OperationStatus)(i % 6);
|
||||||
|
operation.Thumbnail = null;
|
||||||
|
operation.Title = $"Youtube Title Movie Number {i}";
|
||||||
|
operations.Add(operationModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
30
VideoBrowser.Test/Views/SettingsViewTest.cs
Normal file
30
VideoBrowser.Test/Views/SettingsViewTest.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
namespace VideoBrowser.Test.Views
|
||||||
|
{
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Views;
|
||||||
|
using VideoBrowser.Test.Common;
|
||||||
|
using VideoBrowser.Test.TestHelpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="SettingsViewTest" />.
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class SettingsViewTest
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Show_SettingsView.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod, ManualTest]
|
||||||
|
public void Show_SettingsView()
|
||||||
|
{
|
||||||
|
var viewModel = new SettingsViewModel();
|
||||||
|
var view = new SettingsView { DataContext = viewModel };
|
||||||
|
WindowFactory.CreateAndShow(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
38
VideoBrowser.Test/Views/UrlEditorViewTest.cs
Normal file
38
VideoBrowser.Test/Views/UrlEditorViewTest.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
namespace VideoBrowser.Test.Views
|
||||||
|
{
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Core;
|
||||||
|
using VideoBrowser.Test.Common;
|
||||||
|
using VideoBrowser.Test.TestHelpers;
|
||||||
|
using VideoBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Views;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="UrlEditorViewTest" />.
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class UrlEditorViewTest
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Show_UrlEditorView.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod, ManualTest]
|
||||||
|
public void Show_UrlEditorView()
|
||||||
|
{
|
||||||
|
var urlReader = new UrlReader();
|
||||||
|
var settings = new SettingsViewModel();
|
||||||
|
var viewModelA = new UrlEditorViewModel(urlReader, settings) { IsVisible = true, FileName = "Youtube Video File Name", FileSize = "5 MB", Duration = "00:02:45" };
|
||||||
|
var viewModelB = new UrlEditorViewModel(urlReader, settings) { IsVisible = true, FileName = "Youtube Video File Name", FileSize = "1.4 MB", Duration = "00:02:45", IsBusy = true };
|
||||||
|
var stackPanel = new StackPanel();
|
||||||
|
stackPanel.Children.Add(new UrlEditorView { DataContext = viewModelA });
|
||||||
|
stackPanel.Children.Add(new UrlEditorView { DataContext = viewModelB });
|
||||||
|
WindowFactory.CreateAndShow(stackPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
VideoBrowser.Test/key.snk
Normal file
BIN
VideoBrowser.Test/key.snk
Normal file
Binary file not shown.
51
VideoBrowser.sln
Normal file
51
VideoBrowser.sln
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.28307.960
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoBrowser", "VideoBrowser\VideoBrowser.csproj", "{2D8225BC-F5B6-4F29-A9E3-F4694D260597}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoBrowser.Test", "VideoBrowser.Test\VideoBrowser.Test.csproj", "{CEB9D499-9F24-42C0-B6AD-165D2ABF9B7B}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoBrowserTestApp", "VideoBrowserTestApp\VideoBrowserTestApp.csproj", "{78B417A3-4C48-45FF-91FB-66AF9436CD75}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{2D8225BC-F5B6-4F29-A9E3-F4694D260597}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2D8225BC-F5B6-4F29-A9E3-F4694D260597}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2D8225BC-F5B6-4F29-A9E3-F4694D260597}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{2D8225BC-F5B6-4F29-A9E3-F4694D260597}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{2D8225BC-F5B6-4F29-A9E3-F4694D260597}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2D8225BC-F5B6-4F29-A9E3-F4694D260597}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2D8225BC-F5B6-4F29-A9E3-F4694D260597}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{2D8225BC-F5B6-4F29-A9E3-F4694D260597}.Release|x64.Build.0 = Release|x64
|
||||||
|
{CEB9D499-9F24-42C0-B6AD-165D2ABF9B7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CEB9D499-9F24-42C0-B6AD-165D2ABF9B7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CEB9D499-9F24-42C0-B6AD-165D2ABF9B7B}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{CEB9D499-9F24-42C0-B6AD-165D2ABF9B7B}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{CEB9D499-9F24-42C0-B6AD-165D2ABF9B7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CEB9D499-9F24-42C0-B6AD-165D2ABF9B7B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CEB9D499-9F24-42C0-B6AD-165D2ABF9B7B}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{CEB9D499-9F24-42C0-B6AD-165D2ABF9B7B}.Release|x64.Build.0 = Release|x64
|
||||||
|
{78B417A3-4C48-45FF-91FB-66AF9436CD75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{78B417A3-4C48-45FF-91FB-66AF9436CD75}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{78B417A3-4C48-45FF-91FB-66AF9436CD75}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{78B417A3-4C48-45FF-91FB-66AF9436CD75}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{78B417A3-4C48-45FF-91FB-66AF9436CD75}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{78B417A3-4C48-45FF-91FB-66AF9436CD75}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{78B417A3-4C48-45FF-91FB-66AF9436CD75}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{78B417A3-4C48-45FF-91FB-66AF9436CD75}.Release|x64.Build.0 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {66253547-6CF3-47BA-A026-B14989D85653}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
36
VideoBrowser/App.config
Normal file
36
VideoBrowser/App.config
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<configSections>
|
||||||
|
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<section name="VideoBrowser.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
|
||||||
|
</sectionGroup>
|
||||||
|
</configSections>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||||
|
</startup>
|
||||||
|
<userSettings>
|
||||||
|
<VideoBrowser.Properties.Settings>
|
||||||
|
<setting name="WindowPosition" serializeAs="String">
|
||||||
|
<value>0,0</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="WindowWidth" serializeAs="String">
|
||||||
|
<value>1920</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="WindowHeight" serializeAs="String">
|
||||||
|
<value>1080</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="LastUrl" serializeAs="String">
|
||||||
|
<value>https://yoyokits.github.io/VideoBrowser/welcome.html</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="ShowMaxSimDownloads" serializeAs="String">
|
||||||
|
<value>False</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="MaxSimDownloads" serializeAs="String">
|
||||||
|
<value>5</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="WindowState" serializeAs="String">
|
||||||
|
<value>Normal</value>
|
||||||
|
</setting>
|
||||||
|
</VideoBrowser.Properties.Settings>
|
||||||
|
</userSettings>
|
||||||
|
</configuration>
|
||||||
18
VideoBrowser/App.xaml
Normal file
18
VideoBrowser/App.xaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<Application
|
||||||
|
x:Class="VideoBrowser.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Exit="Application_Exit"
|
||||||
|
Startup="OnApplication_Startup"
|
||||||
|
StartupUri="Views\MainWindow.xaml">
|
||||||
|
<Application.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/Generic.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
||||||
50
VideoBrowser/App.xaml.cs
Normal file
50
VideoBrowser/App.xaml.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
namespace VideoBrowser
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Core;
|
||||||
|
using VideoBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for App.xaml.
|
||||||
|
/// </summary>
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnApplication_Startup.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender<see cref="object"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="StartupEventArgs"/>.</param>
|
||||||
|
private void OnApplication_Startup(object sender, StartupEventArgs e)
|
||||||
|
{
|
||||||
|
AppEnvironment.Arguments = e.Args;
|
||||||
|
this.UpdateYoutubeDl();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
|
||||||
|
private void Application_Exit(object sender, ExitEventArgs e)
|
||||||
|
{
|
||||||
|
Cef.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateYoutubeDl()
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var path = YoutubeDl.YouTubeDlPath;
|
||||||
|
ProcessHelper.StartProcess(path, "--update --no-check-certificate", this.UpdateOutput, null, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateOutput(Process process, string output)
|
||||||
|
{
|
||||||
|
Logger.Info($"Youtube-dl message:{output}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
VideoBrowser/Binaries/ffmpeg.exe
Normal file
BIN
VideoBrowser/Binaries/ffmpeg.exe
Normal file
Binary file not shown.
BIN
VideoBrowser/Binaries/youtube-dl.exe
Normal file
BIN
VideoBrowser/Binaries/youtube-dl.exe
Normal file
Binary file not shown.
154
VideoBrowser/Common/AppEnvironment.cs
Normal file
154
VideoBrowser/Common/AppEnvironment.cs
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="AppEnvironment" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class AppEnvironment
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
public const string Name = "Cekli Browser";
|
||||||
|
|
||||||
|
public const string LongName = "Cekli Video Browser and Downloader";
|
||||||
|
|
||||||
|
public const int ProgressUpdateDelay = 250;
|
||||||
|
|
||||||
|
public static readonly string ShortName = Assembly.GetExecutingAssembly().GetName().Name;
|
||||||
|
|
||||||
|
private const string BinariesDirectory = "Binaries";
|
||||||
|
|
||||||
|
private const string JsonDirectory = "Json";
|
||||||
|
|
||||||
|
private const string LogsDirectory = "Logs";
|
||||||
|
|
||||||
|
#endregion Constants
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the AppBinaryDirectory.
|
||||||
|
/// </summary>
|
||||||
|
public static string AppBinaryDirectory => Path.Combine(AppDirectory, BinariesDirectory);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the AppDirectory.
|
||||||
|
/// </summary>
|
||||||
|
public static string AppDirectory => AppDomain.CurrentDomain.BaseDirectory;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Arguments.
|
||||||
|
/// </summary>
|
||||||
|
public static string[] Arguments { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Author.
|
||||||
|
/// </summary>
|
||||||
|
public static string Author => "Yohanes Wahyu Nurcahyo";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the HomeUrl.
|
||||||
|
/// </summary>
|
||||||
|
public static string HomeUrl => "https://yoyokits.github.io/VideoBrowser/welcome.html";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the ProjectUrl.
|
||||||
|
/// </summary>
|
||||||
|
public static string ProjectUrl { get; } = "https://github.com/yoyokits/VideoBrowser";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the UserLocalApplicationData.
|
||||||
|
/// </summary>
|
||||||
|
public static string UserLocalApplicationData { get; } = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the UserProfile.
|
||||||
|
/// </summary>
|
||||||
|
public static string UserProfile { get; } = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the UserVideoFolder.
|
||||||
|
/// </summary>
|
||||||
|
public static string UserVideoFolder { get; } = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Version.
|
||||||
|
/// </summary>
|
||||||
|
public static string Version { get; } = $"{Assembly.GetExecutingAssembly().GetName().Version.ToString()}";
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the local app data directory for this program. Also makes sure the directory exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="string"/>.</returns>
|
||||||
|
public static string GetAppDataDirectory()
|
||||||
|
{
|
||||||
|
var path = Path.Combine(UserLocalApplicationData, AppEnvironment.ShortName);
|
||||||
|
if (!Directory.Exists(path))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The application folder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="specialFolder">The specialFolder<see cref="Environment.SpecialFolder"/>.</param>
|
||||||
|
/// <returns>The <see cref="string"/>.</returns>
|
||||||
|
public static string GetFolder(Environment.SpecialFolder specialFolder) => Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the json directory for this program. Also makes sure the directory exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="string"/>.</returns>
|
||||||
|
public static string GetJsonDirectory()
|
||||||
|
{
|
||||||
|
var path = Path.Combine(GetAppDataDirectory(), JsonDirectory);
|
||||||
|
if (!Directory.Exists(path))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the logs directory for this program. Also makes sure the directory exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="string"/>.</returns>
|
||||||
|
public static string GetLogsDirectory()
|
||||||
|
{
|
||||||
|
var path = Path.Combine(GetAppDataDirectory(), LogsDirectory);
|
||||||
|
if (!Directory.Exists(path))
|
||||||
|
Directory.CreateDirectory(path);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetUserLocalApplicationData.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="string"/>.</returns>
|
||||||
|
public static string GetUserLocalApplicationData()
|
||||||
|
{
|
||||||
|
var userFolder = UserLocalApplicationData;
|
||||||
|
var appFolder = Path.Combine(userFolder, ShortName);
|
||||||
|
if (!Directory.Exists(appFolder))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(appFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
return appFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
135
VideoBrowser/Common/ByteSizeFormatProvider.cs
Normal file
135
VideoBrowser/Common/ByteSizeFormatProvider.cs
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="ByteFormatProvider" />
|
||||||
|
/// </summary>
|
||||||
|
public class ByteFormatProvider : IFormatProvider, ICustomFormatter
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
private const string FileSizeFormat = "fs";
|
||||||
|
|
||||||
|
private const decimal OneGigaByte = OneMegaByte * 1024M;
|
||||||
|
|
||||||
|
private const decimal OneKiloByte = 1024M;
|
||||||
|
|
||||||
|
private const decimal OneMegaByte = OneKiloByte * 1024M;
|
||||||
|
|
||||||
|
private const string SpeedFormat = "s";
|
||||||
|
|
||||||
|
#endregion Constants
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Lock
|
||||||
|
/// </summary>
|
||||||
|
private object Lock { get; } = new object();
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Format
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">The format<see cref="string"/></param>
|
||||||
|
/// <param name="arg">The arg<see cref="object"/></param>
|
||||||
|
/// <param name="formatProvider">The formatProvider<see cref="IFormatProvider"/></param>
|
||||||
|
/// <returns>The <see cref="string"/></returns>
|
||||||
|
public string Format(string format, object arg, IFormatProvider formatProvider)
|
||||||
|
{
|
||||||
|
lock (this.Lock)
|
||||||
|
{
|
||||||
|
if (format == null || (!format.StartsWith(FileSizeFormat) && !format.StartsWith(SpeedFormat)))
|
||||||
|
{
|
||||||
|
return DefaultFormat(format, arg, formatProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg is string)
|
||||||
|
{
|
||||||
|
return DefaultFormat(format, arg, formatProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
decimal size;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
size = Convert.ToDecimal(arg);
|
||||||
|
}
|
||||||
|
catch (InvalidCastException)
|
||||||
|
{
|
||||||
|
return DefaultFormat(format, arg, formatProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
string suffix;
|
||||||
|
|
||||||
|
if (size > OneGigaByte)
|
||||||
|
{
|
||||||
|
size /= OneGigaByte;
|
||||||
|
suffix = "GB";
|
||||||
|
}
|
||||||
|
else if (size > OneMegaByte)
|
||||||
|
{
|
||||||
|
size /= OneMegaByte;
|
||||||
|
suffix = "MB";
|
||||||
|
}
|
||||||
|
else if (size > OneKiloByte)
|
||||||
|
{
|
||||||
|
size /= OneKiloByte;
|
||||||
|
suffix = "KB";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
suffix = "Bytes";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.StartsWith(SpeedFormat))
|
||||||
|
{
|
||||||
|
suffix += "/s";
|
||||||
|
}
|
||||||
|
|
||||||
|
var postion = format.StartsWith(SpeedFormat) ? SpeedFormat.Length : FileSizeFormat.Length;
|
||||||
|
var precision = format.Substring(postion);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(precision))
|
||||||
|
{
|
||||||
|
precision = "2";
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format("{0:N" + precision + "}{1}", size, " " + suffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetFormat
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="formatType">The formatType<see cref="Type"/></param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
public object GetFormat(Type formatType)
|
||||||
|
{
|
||||||
|
return formatType == typeof(ICustomFormatter) ? (this) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The DefaultFormat
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">The format<see cref="string"/></param>
|
||||||
|
/// <param name="arg">The arg<see cref="object"/></param>
|
||||||
|
/// <param name="formatProvider">The formatProvider<see cref="IFormatProvider"/></param>
|
||||||
|
/// <returns>The <see cref="string"/></returns>
|
||||||
|
private static string DefaultFormat(string format, object arg, IFormatProvider formatProvider)
|
||||||
|
{
|
||||||
|
if (arg is IFormattable formattableArg)
|
||||||
|
{
|
||||||
|
return formattableArg.ToString(format, formatProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
return arg.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
23
VideoBrowser/Common/Epsilon.cs
Normal file
23
VideoBrowser/Common/Epsilon.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="Epsilon" />
|
||||||
|
/// </summary>
|
||||||
|
public static class Epsilon
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The epsilon for angle.
|
||||||
|
/// </summary>
|
||||||
|
public const double Angle = 0.01;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The epsilon for default.
|
||||||
|
/// </summary>
|
||||||
|
public const double Default = 0.00000000001;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The epsilon for meter.
|
||||||
|
/// </summary>
|
||||||
|
public const double Meter = 0.00001;
|
||||||
|
}
|
||||||
|
}
|
||||||
169
VideoBrowser/Common/Log.cs
Normal file
169
VideoBrowser/Common/Log.cs
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
using log4net;
|
||||||
|
using log4net.Appender;
|
||||||
|
using log4net.Core;
|
||||||
|
using log4net.Layout;
|
||||||
|
using log4net.Repository.Hierarchy;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="Logging.Logger" />
|
||||||
|
/// Log the important process to trace the last processes before error occurs.
|
||||||
|
/// </summary>
|
||||||
|
public static class Logger
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes static members of the <see cref="Logger"/> class.
|
||||||
|
/// </summary>
|
||||||
|
static Logger()
|
||||||
|
{
|
||||||
|
Setup(nameof(VideoBrowser));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Log.
|
||||||
|
/// </summary>
|
||||||
|
public static ILog Log { get; } = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the LogFilePath.
|
||||||
|
/// </summary>
|
||||||
|
public static string LogFilePath { get; private set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Debug Log.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message<see cref="object"/>.</param>
|
||||||
|
public static void Debug(object message)
|
||||||
|
{
|
||||||
|
Log.Debug(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Error Log.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message<see cref="object"/>.</param>
|
||||||
|
public static void Error(object message)
|
||||||
|
{
|
||||||
|
Log.Error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Fatal Log.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message<see cref="object"/>.</param>
|
||||||
|
public static void Fatal(object message)
|
||||||
|
{
|
||||||
|
Log.Fatal(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Info.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message<see cref="object"/>.</param>
|
||||||
|
public static void Info(object message = null)
|
||||||
|
{
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
message = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Info(message);
|
||||||
|
System.Diagnostics.Trace.WriteLine(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Info Log.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The source<see cref="object"/>.</param>
|
||||||
|
/// <param name="message">The message<see cref="object"/>.</param>
|
||||||
|
public static void Info(this object source, object message)
|
||||||
|
{
|
||||||
|
Log.Info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Setup.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="appName">The appName<see cref="string"/>.</param>
|
||||||
|
public static void Setup(string appName)
|
||||||
|
{
|
||||||
|
LogFilePath = GetLogFilePath(appName);
|
||||||
|
var entryAssembly = Assembly.GetExecutingAssembly();
|
||||||
|
var hierarchy = (Hierarchy)LogManager.GetRepository(entryAssembly);
|
||||||
|
|
||||||
|
var patternLayout = new PatternLayout
|
||||||
|
{
|
||||||
|
ConversionPattern = "%date [%thread] %-5level %logger - %message%newline"
|
||||||
|
};
|
||||||
|
|
||||||
|
patternLayout.ActivateOptions();
|
||||||
|
|
||||||
|
var roller = new RollingFileAppender
|
||||||
|
{
|
||||||
|
AppendToFile = false,
|
||||||
|
File = LogFilePath,
|
||||||
|
Layout = patternLayout,
|
||||||
|
MaxSizeRollBackups = 5,
|
||||||
|
MaximumFileSize = "1GB",
|
||||||
|
RollingStyle = RollingFileAppender.RollingMode.Size,
|
||||||
|
StaticLogFileName = true
|
||||||
|
};
|
||||||
|
roller.ActivateOptions();
|
||||||
|
hierarchy.Root.AddAppender(roller);
|
||||||
|
|
||||||
|
var memory = new MemoryAppender();
|
||||||
|
memory.ActivateOptions();
|
||||||
|
hierarchy.Root.AddAppender(memory);
|
||||||
|
|
||||||
|
hierarchy.Root.Level = Level.Info;
|
||||||
|
hierarchy.Configured = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Warn.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The source<see cref="object"/>.</param>
|
||||||
|
/// <param name="message">The message<see cref="object"/>.</param>
|
||||||
|
public static void Warn(this object source, object message)
|
||||||
|
{
|
||||||
|
Log.Warn(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves given Exception's stack trace to a readable file in the local application data folder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ex">The Exception to save.</param>
|
||||||
|
public static void WriteException(Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Info(ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetLogFilePath.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="appName">The appName<see cref="string"/>.</param>
|
||||||
|
/// <returns>The <see cref="string"/>.</returns>
|
||||||
|
internal static string GetLogFilePath(string appName)
|
||||||
|
{
|
||||||
|
var folder = AppEnvironment.GetUserLocalApplicationData();
|
||||||
|
var path = Path.Combine(folder, $"{appName}.log");
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
31
VideoBrowser/Common/NotifyPropertyChanged.cs
Normal file
31
VideoBrowser/Common/NotifyPropertyChanged.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="NotifyPropertyChanged" />
|
||||||
|
/// Standard INotifyPropertyChanged implementation.
|
||||||
|
/// </summary>
|
||||||
|
public class NotifyPropertyChanged : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the PropertyChanged
|
||||||
|
/// </summary>
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The property changed handler
|
||||||
|
/// </summary>
|
||||||
|
protected PropertyChangedEventHandler PropertyChangedHandler => this.PropertyChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnPropertyChanged
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyName">The <see cref="string"/></param>
|
||||||
|
public void OnPropertyChanged([CallerMemberName]string propertyName = null)
|
||||||
|
{
|
||||||
|
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
VideoBrowser/Common/OutputFormat.cs
Normal file
37
VideoBrowser/Common/OutputFormat.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
#region Enums
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the OutputFormat
|
||||||
|
/// </summary>
|
||||||
|
public enum OutputFormat
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the Webm
|
||||||
|
/// </summary>
|
||||||
|
Webm,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the MP4
|
||||||
|
/// </summary>
|
||||||
|
MP4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the MP3
|
||||||
|
/// </summary>
|
||||||
|
MP3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the M4A
|
||||||
|
/// </summary>
|
||||||
|
M4A,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the Vorbis
|
||||||
|
/// </summary>
|
||||||
|
Vorbis
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Enums
|
||||||
|
}
|
||||||
92
VideoBrowser/Common/Percentage.cs
Normal file
92
VideoBrowser/Common/Percentage.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="Percentage" />
|
||||||
|
/// </summary>
|
||||||
|
internal struct Percentage : IEquatable<Percentage>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref=""/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="percent">The percent<see cref="double"/></param>
|
||||||
|
public Percentage(double percent)
|
||||||
|
{
|
||||||
|
this.Percent = percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Empty
|
||||||
|
/// </summary>
|
||||||
|
public static Percentage Empty { get; } = new Percentage(double.NaN);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether IsEmpty
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEmpty => double.IsNaN(this.Percent);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Normalized
|
||||||
|
/// </summary>
|
||||||
|
public double Normalized => this.Percent * 0.01;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Percent
|
||||||
|
/// </summary>
|
||||||
|
public double Percent { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Equals
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/></param>
|
||||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return base.Equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Equals
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other<see cref="Percentage"/></param>
|
||||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||||
|
public bool Equals(Percentage other)
|
||||||
|
{
|
||||||
|
var equals = this.Percent.IsEqualTo(other.Percent);
|
||||||
|
return equals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetHashCode
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="int"/></returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return this.Percent.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ToString
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="string"/></returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var message = $"{this.Percent.Format()}%";
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Percentage left, Percentage right)
|
||||||
|
{
|
||||||
|
var equals = left.Percent.IsEqualTo(right.Percent);
|
||||||
|
return equals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Percentage left, Percentage right)
|
||||||
|
{
|
||||||
|
var equals = left.Percent.IsEqualTo(right.Percent);
|
||||||
|
return !equals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
VideoBrowser/Common/Range.cs
Normal file
107
VideoBrowser/Common/Range.cs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using VideoBrowser.If;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="Range{T}" />
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public struct Range<T> : IRange<T> where T : IComparable<T>
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref=""/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">The start.</param>
|
||||||
|
/// <param name="end">The end.</param>
|
||||||
|
public Range(T start, T end)
|
||||||
|
{
|
||||||
|
this.Start = start;
|
||||||
|
this.End = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the End
|
||||||
|
/// </summary>
|
||||||
|
public T End { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Start
|
||||||
|
/// </summary>
|
||||||
|
public T Start { get; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Equals
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other<see cref="IRange{T}"/></param>
|
||||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||||
|
public bool Equals(IRange<T> other)
|
||||||
|
{
|
||||||
|
return this.Start.Equals(other.Start) && this.End.Equals(other.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Equals
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The <see cref="object"/></param>
|
||||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return this == (Range<T>)obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetHashCode
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="int"/></returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
var startHash = this.Start.GetHashCode();
|
||||||
|
var endHash = this.End.GetHashCode();
|
||||||
|
return startHash ^ (startHash << 8) ^ endHash ^ (endHash << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ToString
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="string"/></returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Start:{this.Start};End:{this.End}";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the operator ==.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The left.</param>
|
||||||
|
/// <param name="right">The right.</param>
|
||||||
|
/// <returns> The result of the operator. </returns>
|
||||||
|
public static bool operator ==(Range<T> left, Range<T> right)
|
||||||
|
{
|
||||||
|
return Equals(left.Start, right.Start) && Equals(left.End, right.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the operator !=.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The left.</param>
|
||||||
|
/// <param name="right">The right.</param>
|
||||||
|
/// <returns> The result of the operator. </returns>
|
||||||
|
public static bool operator !=(Range<T> left, Range<T> right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
120
VideoBrowser/Common/RangeDouble.cs
Normal file
120
VideoBrowser/Common/RangeDouble.cs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
using VideoBrowser.If;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="RangeDouble" />
|
||||||
|
/// </summary>
|
||||||
|
public struct RangeDouble : IRange<double>
|
||||||
|
{
|
||||||
|
private const double PRECISION = 1E-6;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref=""/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">The start<see cref="double"/></param>
|
||||||
|
/// <param name="end">The end<see cref="double"/></param>
|
||||||
|
/// <param name="allowInvert">The allowInvert<see cref="bool"/></param>
|
||||||
|
public RangeDouble(double start, double end, bool allowInvert = false)
|
||||||
|
{
|
||||||
|
if (!allowInvert && start >= end)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"{nameof(start)} is equal or greater than {nameof(end)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Start = start;
|
||||||
|
this.End = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Empty
|
||||||
|
/// </summary>
|
||||||
|
public static RangeDouble Empty { get; } = new RangeDouble();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the End
|
||||||
|
/// </summary>
|
||||||
|
public double End { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Start
|
||||||
|
/// </summary>
|
||||||
|
public double Start { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Equals
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other<see cref="IRange{double}"/></param>
|
||||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||||
|
public bool Equals(IRange<double> other)
|
||||||
|
{
|
||||||
|
return Equals(this.Start, other.Start) && Equals(this.End, other.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Equals
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The <see cref="object"/></param>
|
||||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (!(obj is RangeDouble))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this == (RangeDouble)obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Equalses the specified other.</summary>
|
||||||
|
/// <param name="other">The other.</param>
|
||||||
|
public bool Equals(RangeDouble other)
|
||||||
|
{
|
||||||
|
return this.Start.IsEqualTo(other.Start, PRECISION) && this.End.IsEqualTo(other.End, PRECISION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetHashCode
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="int"/></returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
var startHash = this.Start.GetHashCode();
|
||||||
|
var endHash = this.End.GetHashCode();
|
||||||
|
return startHash ^ (startHash << 8) ^ endHash ^ (endHash << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ToString
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="string"/></returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Start:{this.Start.Format()};End:{this.End.Format()};Length:{this.Length().Format()}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the operator ==.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The left.</param>
|
||||||
|
/// <param name="right">The right.</param>
|
||||||
|
/// <returns> The result of the operator. </returns>
|
||||||
|
public static bool operator ==(RangeDouble left, RangeDouble right)
|
||||||
|
{
|
||||||
|
return left.Start.IsEqualTo(right.Start, PRECISION) && left.End.IsEqualTo(right.End, PRECISION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the operator !=.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The left.</param>
|
||||||
|
/// <param name="right">The right.</param>
|
||||||
|
/// <returns> The result of the operator. </returns>
|
||||||
|
public static bool operator !=(RangeDouble left, RangeDouble right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
112
VideoBrowser/Common/RangeInt.cs
Normal file
112
VideoBrowser/Common/RangeInt.cs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using VideoBrowser.If;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="RangeInt" />
|
||||||
|
/// </summary>
|
||||||
|
public struct RangeInt : IRange<int>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref=""/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">The start<see cref="int"/></param>
|
||||||
|
/// <param name="end">The end<see cref="int"/></param>
|
||||||
|
/// <param name="allowInvert">The allowInvert<see cref="bool"/></param>
|
||||||
|
public RangeInt(int start, int end, bool allowInvert = false)
|
||||||
|
{
|
||||||
|
if (!allowInvert && start > end)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"{nameof(start)} is equal or greater than {nameof(end)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Start = start;
|
||||||
|
this.End = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the End
|
||||||
|
/// </summary>
|
||||||
|
public int End { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Start
|
||||||
|
/// </summary>
|
||||||
|
public int Start { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Equals
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other<see cref="IRange{int}"/></param>
|
||||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||||
|
public bool Equals(IRange<int> other)
|
||||||
|
{
|
||||||
|
return Equals(this.Start, other.Start) && Equals(this.End, other.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Equals
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The <see cref="object"/></param>
|
||||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (!(obj is RangeInt))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this == (RangeInt)obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Equalses the specified other.</summary>
|
||||||
|
/// <param name="other">The other.</param>
|
||||||
|
public bool Equals(RangeInt other)
|
||||||
|
{
|
||||||
|
return this.Start == other.Start && this.End == other.End;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetHashCode
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="int"/></returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
var startHash = this.Start.GetHashCode();
|
||||||
|
var endHash = this.End.GetHashCode();
|
||||||
|
return startHash ^ (startHash << 8) ^ endHash ^ (endHash << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ToString
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="string"/></returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Start:{this.Start};End:{this.End};Length:{this.End - this.Start}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the operator ==.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The left.</param>
|
||||||
|
/// <param name="right">The right.</param>
|
||||||
|
/// <returns> The result of the operator. </returns>
|
||||||
|
public static bool operator ==(RangeInt left, RangeInt right)
|
||||||
|
{
|
||||||
|
return left.Start == right.Start && left.End == right.End;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the operator !=.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The left.</param>
|
||||||
|
/// <param name="right">The right.</param>
|
||||||
|
/// <returns> The result of the operator. </returns>
|
||||||
|
public static bool operator !=(RangeInt left, RangeInt right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
61
VideoBrowser/Common/RelayCommand.cs
Normal file
61
VideoBrowser/Common/RelayCommand.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The WPF default command.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="System.Windows.Input.ICommand" />
|
||||||
|
public class RelayCommand : ICommand
|
||||||
|
{
|
||||||
|
private readonly Func<object, bool> _canExecute;
|
||||||
|
|
||||||
|
private readonly Action<object> _execute;
|
||||||
|
|
||||||
|
private readonly string _name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RelayCommand"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="execute">The execute.</param>
|
||||||
|
/// <param name="canExecute">The can execute.</param>
|
||||||
|
public RelayCommand(Action<object> execute, string name = "", Func<object, bool> canExecute = null)
|
||||||
|
{
|
||||||
|
this._execute = execute;
|
||||||
|
this._name = name;
|
||||||
|
this._canExecute = canExecute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when changes occur that affect whether or not the command should execute.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler CanExecuteChanged
|
||||||
|
{
|
||||||
|
add { CommandManager.RequerySuggested += value; }
|
||||||
|
remove { CommandManager.RequerySuggested -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the method that determines whether the command can execute in its current state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to <see langword="null" />.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="true" /> if this command can be executed; otherwise, <see langword="false" />.
|
||||||
|
/// </returns>
|
||||||
|
public bool CanExecute(object parameter)
|
||||||
|
{
|
||||||
|
return this._canExecute == null || this._canExecute(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the method to be called when the command is invoked.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to <see langword="null" />.</param>
|
||||||
|
public void Execute(object parameter)
|
||||||
|
{
|
||||||
|
this._execute(parameter);
|
||||||
|
Logger.Info($"{nameof(RelayCommand)} {this._name} is executed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
VideoBrowser/Common/VideoState.cs
Normal file
32
VideoBrowser/Common/VideoState.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
namespace VideoBrowser.Common
|
||||||
|
{
|
||||||
|
#region Enums
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the VideoState
|
||||||
|
/// </summary>
|
||||||
|
public enum VideoState
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the None
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the Downloading
|
||||||
|
/// </summary>
|
||||||
|
Downloading,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the Downloaded
|
||||||
|
/// </summary>
|
||||||
|
Downloaded,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the Error
|
||||||
|
/// </summary>
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Enums
|
||||||
|
}
|
||||||
726
VideoBrowser/Controls/AdornedControl/AdornedControl.cs
Normal file
726
VideoBrowser/Controls/AdornedControl/AdornedControl.cs
Normal file
@@ -0,0 +1,726 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Animation;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace VideoBrowser.Controls.AdornedControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A content control that allows an adorner for the content to
|
||||||
|
/// be defined in XAML.
|
||||||
|
/// </summary>
|
||||||
|
public class AdornedControl : ContentControl
|
||||||
|
{
|
||||||
|
#region Dependency Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dependency properties.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty IsAdornerVisibleProperty =
|
||||||
|
DependencyProperty.Register("IsAdornerVisible", typeof(bool), typeof(AdornedControl),
|
||||||
|
new FrameworkPropertyMetadata(IsAdornerVisible_PropertyChanged));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty AdornerContentProperty =
|
||||||
|
DependencyProperty.Register("AdornerContent", typeof(FrameworkElement), typeof(AdornedControl),
|
||||||
|
new FrameworkPropertyMetadata(AdornerContent_PropertyChanged));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty HorizontalAdornerPlacementProperty =
|
||||||
|
DependencyProperty.Register("HorizontalAdornerPlacement", typeof(AdornerPlacement), typeof(AdornedControl),
|
||||||
|
new FrameworkPropertyMetadata(AdornerPlacement.Inside));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty VerticalAdornerPlacementProperty =
|
||||||
|
DependencyProperty.Register("VerticalAdornerPlacement", typeof(AdornerPlacement), typeof(AdornedControl),
|
||||||
|
new FrameworkPropertyMetadata(AdornerPlacement.Inside));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty AdornerOffsetXProperty =
|
||||||
|
DependencyProperty.Register("AdornerOffsetX", typeof(double), typeof(AdornedControl));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty AdornerOffsetYProperty =
|
||||||
|
DependencyProperty.Register("AdornerOffsetY", typeof(double), typeof(AdornedControl));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty IsMouseOverShowEnabledProperty =
|
||||||
|
DependencyProperty.Register("IsMouseOverShowEnabled", typeof(bool), typeof(AdornedControl),
|
||||||
|
new FrameworkPropertyMetadata(true, IsMouseOverShowEnabled_PropertyChanged));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty FadeInTimeProperty =
|
||||||
|
DependencyProperty.Register("FadeInTime", typeof(double), typeof(AdornedControl),
|
||||||
|
new FrameworkPropertyMetadata(0.25));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty FadeOutTimeProperty =
|
||||||
|
DependencyProperty.Register("FadeOutTime", typeof(double), typeof(AdornedControl),
|
||||||
|
new FrameworkPropertyMetadata(1.0));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty CloseAdornerTimeOutProperty =
|
||||||
|
DependencyProperty.Register("CloseAdornerTimeOut", typeof(double), typeof(AdornedControl),
|
||||||
|
new FrameworkPropertyMetadata(2.0, CloseAdornerTimeOut_PropertyChanged));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty AdornedTemplatePartNameProperty =
|
||||||
|
DependencyProperty.Register("AdornedTemplatePartName", typeof(string), typeof(AdornedControl),
|
||||||
|
new FrameworkPropertyMetadata(null));
|
||||||
|
|
||||||
|
#endregion Dependency Properties
|
||||||
|
|
||||||
|
#region Commands
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Commands.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly RoutedCommand ShowAdornerCommand = new RoutedCommand("ShowAdorner", typeof(AdornedControl));
|
||||||
|
|
||||||
|
public static readonly RoutedCommand FadeInAdornerCommand = new RoutedCommand("FadeInAdorner", typeof(AdornedControl));
|
||||||
|
public static readonly RoutedCommand HideAdornerCommand = new RoutedCommand("HideAdorner", typeof(AdornedControl));
|
||||||
|
public static readonly RoutedCommand FadeOutAdornerCommand = new RoutedCommand("FadeOutAdorner", typeof(AdornedControl));
|
||||||
|
|
||||||
|
#endregion Commands
|
||||||
|
|
||||||
|
public AdornedControl()
|
||||||
|
{
|
||||||
|
this.Focusable = false; // By default don't want 'AdornedControl' to be focusable.
|
||||||
|
|
||||||
|
this.DataContextChanged += new DependencyPropertyChangedEventHandler(AdornedControl_DataContextChanged);
|
||||||
|
|
||||||
|
closeAdornerTimer.Tick += new EventHandler(closeAdornerTimer_Tick);
|
||||||
|
closeAdornerTimer.Interval = TimeSpan.FromSeconds(CloseAdornerTimeOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show the adorner.
|
||||||
|
/// </summary>
|
||||||
|
public void ShowAdorner()
|
||||||
|
{
|
||||||
|
IsAdornerVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hide the adorner.
|
||||||
|
/// </summary>
|
||||||
|
public void HideAdorner()
|
||||||
|
{
|
||||||
|
IsAdornerVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fade the adorner in and make it visible.
|
||||||
|
/// </summary>
|
||||||
|
public void FadeInAdorner()
|
||||||
|
{
|
||||||
|
if (adornerShowState == AdornerShowState.Visible ||
|
||||||
|
adornerShowState == AdornerShowState.FadingIn)
|
||||||
|
{
|
||||||
|
// Already visible or fading in.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ShowAdorner();
|
||||||
|
|
||||||
|
if (adornerShowState != AdornerShowState.FadingOut)
|
||||||
|
{
|
||||||
|
adorner.Opacity = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleAnimation doubleAnimation = new DoubleAnimation(1.0, new Duration(TimeSpan.FromSeconds(FadeInTime)));
|
||||||
|
doubleAnimation.Completed += new EventHandler(fadeInAnimation_Completed);
|
||||||
|
doubleAnimation.Freeze();
|
||||||
|
|
||||||
|
adorner.BeginAnimation(FrameworkElement.OpacityProperty, doubleAnimation);
|
||||||
|
|
||||||
|
adornerShowState = AdornerShowState.FadingIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fade the adorner out and make it visible.
|
||||||
|
/// </summary>
|
||||||
|
public void FadeOutAdorner()
|
||||||
|
{
|
||||||
|
if (adornerShowState == AdornerShowState.FadingOut)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Already fading out.
|
||||||
|
//
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adornerShowState == AdornerShowState.Hidden)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Adorner has already been hidden.
|
||||||
|
//
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleAnimation fadeOutAnimation = new DoubleAnimation(0.0, new Duration(TimeSpan.FromSeconds(FadeOutTime)));
|
||||||
|
fadeOutAnimation.Completed += new EventHandler(fadeOutAnimation_Completed);
|
||||||
|
fadeOutAnimation.Freeze();
|
||||||
|
|
||||||
|
adorner.BeginAnimation(FrameworkElement.OpacityProperty, fadeOutAnimation);
|
||||||
|
|
||||||
|
adornerShowState = AdornerShowState.FadingOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows or hides the adorner.
|
||||||
|
/// Set to 'true' to show the adorner or 'false' to hide the adorner.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAdornerVisible
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (bool)GetValue(IsAdornerVisibleProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(IsAdornerVisibleProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used in XAML to define the UI content of the adorner.
|
||||||
|
/// </summary>
|
||||||
|
public FrameworkElement AdornerContent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (FrameworkElement)GetValue(AdornerContentProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(AdornerContentProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the horizontal placement of the adorner relative to the adorned control.
|
||||||
|
/// </summary>
|
||||||
|
public AdornerPlacement HorizontalAdornerPlacement
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (AdornerPlacement)GetValue(HorizontalAdornerPlacementProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(HorizontalAdornerPlacementProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the vertical placement of the adorner relative to the adorned control.
|
||||||
|
/// </summary>
|
||||||
|
public AdornerPlacement VerticalAdornerPlacement
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (AdornerPlacement)GetValue(VerticalAdornerPlacementProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(VerticalAdornerPlacementProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// X offset of the adorner.
|
||||||
|
/// </summary>
|
||||||
|
public double AdornerOffsetX
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (double)GetValue(AdornerOffsetXProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(AdornerOffsetXProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Y offset of the adorner.
|
||||||
|
/// </summary>
|
||||||
|
public double AdornerOffsetY
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (double)GetValue(AdornerOffsetYProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(AdornerOffsetYProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set to 'true' to make the adorner automatically fade-in and become visible when the mouse is hovered
|
||||||
|
/// over the adorned control. Also the adorner automatically fades-out when the mouse cursor is moved
|
||||||
|
/// aware from the adorned control (and the adorner).
|
||||||
|
/// </summary>
|
||||||
|
public bool IsMouseOverShowEnabled
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (bool)GetValue(IsMouseOverShowEnabledProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(IsMouseOverShowEnabledProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the time (in seconds) it takes to fade in the adorner.
|
||||||
|
/// </summary>
|
||||||
|
public double FadeInTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (double)GetValue(FadeInTimeProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(FadeInTimeProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the time (in seconds) it takes to fade out the adorner.
|
||||||
|
/// </summary>
|
||||||
|
public double FadeOutTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (double)GetValue(FadeOutTimeProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(FadeOutTimeProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the time (in seconds) after the mouse cursor moves away from the
|
||||||
|
/// adorned control (or the adorner) when the adorner begins to fade out.
|
||||||
|
/// </summary>
|
||||||
|
public double CloseAdornerTimeOut
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (double)GetValue(CloseAdornerTimeOutProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(CloseAdornerTimeOutProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// By default this property is set to null.
|
||||||
|
/// When set to non-null it specifies the part name of a UI element
|
||||||
|
/// in the visual tree of the AdornedControl content that is to be adorned.
|
||||||
|
/// When this property is null it is the AdornerControl content that is adorned,
|
||||||
|
/// however when it is set the visual-tree is searched for a UI element that has the
|
||||||
|
/// specified part name, if the part is found then that UI element is adorned, otherwise
|
||||||
|
/// an exception "Failed to find part ..." is thrown. ///
|
||||||
|
/// </summary>
|
||||||
|
public string AdornedTemplatePartName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (string)GetValue(AdornedTemplatePartNameProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(AdornedTemplatePartNameProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Private Data Members
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command bindings.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly CommandBinding ShowAdornerCommandBinding = new CommandBinding(ShowAdornerCommand, ShowAdornerCommand_Executed);
|
||||||
|
|
||||||
|
private static readonly CommandBinding FadeInAdornerCommandBinding = new CommandBinding(FadeInAdornerCommand, FadeInAdornerCommand_Executed);
|
||||||
|
private static readonly CommandBinding HideAdornerCommandBinding = new CommandBinding(HideAdornerCommand, HideAdornerCommand_Executed);
|
||||||
|
private static readonly CommandBinding FadeOutAdornerCommandBinding = new CommandBinding(FadeInAdornerCommand, FadeOutAdornerCommand_Executed);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the current show/hide state of the adorner.
|
||||||
|
/// </summary>
|
||||||
|
private enum AdornerShowState
|
||||||
|
{
|
||||||
|
Visible,
|
||||||
|
Hidden,
|
||||||
|
FadingIn,
|
||||||
|
FadingOut,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the current show/hide state of the adorner.
|
||||||
|
/// </summary>
|
||||||
|
private AdornerShowState adornerShowState = AdornerShowState.Hidden;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Caches the adorner layer.
|
||||||
|
/// </summary>
|
||||||
|
private AdornerLayer adornerLayer = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The actual adorner create to contain our 'adorner UI content'.
|
||||||
|
/// </summary>
|
||||||
|
private FrameworkElementAdorner adorner = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This timer is used to fade out and close the adorner.
|
||||||
|
/// </summary>
|
||||||
|
private DispatcherTimer closeAdornerTimer = new DispatcherTimer();
|
||||||
|
|
||||||
|
#endregion Private Data Members
|
||||||
|
|
||||||
|
#region Private/Internal Functions
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Static constructor to register command bindings.
|
||||||
|
/// </summary>
|
||||||
|
static AdornedControl()
|
||||||
|
{
|
||||||
|
CommandManager.RegisterClassCommandBinding(typeof(AdornedControl), ShowAdornerCommandBinding);
|
||||||
|
CommandManager.RegisterClassCommandBinding(typeof(AdornedControl), FadeOutAdornerCommandBinding);
|
||||||
|
CommandManager.RegisterClassCommandBinding(typeof(AdornedControl), HideAdornerCommandBinding);
|
||||||
|
CommandManager.RegisterClassCommandBinding(typeof(AdornedControl), FadeInAdornerCommandBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the DataContext of the adorned control changes.
|
||||||
|
/// </summary>
|
||||||
|
private void AdornedControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
UpdateAdornerDataContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the DataContext of the adorner from the adorned control.
|
||||||
|
/// </summary>
|
||||||
|
private void UpdateAdornerDataContext()
|
||||||
|
{
|
||||||
|
if (this.AdornerContent != null)
|
||||||
|
{
|
||||||
|
this.AdornerContent.DataContext = this.DataContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the Show command is executed.
|
||||||
|
/// </summary>
|
||||||
|
private static void ShowAdornerCommand_Executed(object target, ExecutedRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
AdornedControl c = (AdornedControl)target;
|
||||||
|
c.ShowAdorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the FadeIn command is executed.
|
||||||
|
/// </summary>
|
||||||
|
private static void FadeInAdornerCommand_Executed(object target, ExecutedRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
AdornedControl c = (AdornedControl)target;
|
||||||
|
c.FadeOutAdorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the Hide command is executed.
|
||||||
|
/// </summary>
|
||||||
|
private static void HideAdornerCommand_Executed(object target, ExecutedRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
AdornedControl c = (AdornedControl)target;
|
||||||
|
c.HideAdorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the FadeOut command is executed.
|
||||||
|
/// </summary>
|
||||||
|
private static void FadeOutAdornerCommand_Executed(object target, ExecutedRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
AdornedControl c = (AdornedControl)target;
|
||||||
|
c.FadeOutAdorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the value of IsAdornerVisible has changed.
|
||||||
|
/// </summary>
|
||||||
|
private static void IsAdornerVisible_PropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
AdornedControl c = (AdornedControl)o;
|
||||||
|
c.ShowOrHideAdornerInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the IsMouseOverShowEnabled property has changed.
|
||||||
|
/// </summary>
|
||||||
|
private static void IsMouseOverShowEnabled_PropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
AdornedControl c = (AdornedControl)o;
|
||||||
|
c.closeAdornerTimer.Stop();
|
||||||
|
c.HideAdorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the CloseAdornerTimeOut property has change.
|
||||||
|
/// </summary>
|
||||||
|
private static void CloseAdornerTimeOut_PropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
AdornedControl c = (AdornedControl)o;
|
||||||
|
c.closeAdornerTimer.Interval = TimeSpan.FromSeconds(c.CloseAdornerTimeOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the value of AdornerContent has changed.
|
||||||
|
/// </summary>
|
||||||
|
private static void AdornerContent_PropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
AdornedControl c = (AdornedControl)o;
|
||||||
|
c.ShowOrHideAdornerInternal();
|
||||||
|
|
||||||
|
FrameworkElement oldAdornerContent = (FrameworkElement)e.OldValue;
|
||||||
|
if (oldAdornerContent != null)
|
||||||
|
{
|
||||||
|
oldAdornerContent.MouseEnter -= new MouseEventHandler(c.adornerContent_MouseEnter);
|
||||||
|
oldAdornerContent.MouseLeave -= new MouseEventHandler(c.adornerContent_MouseLeave);
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameworkElement newAdornerContent = (FrameworkElement)e.NewValue;
|
||||||
|
if (newAdornerContent != null)
|
||||||
|
{
|
||||||
|
newAdornerContent.MouseEnter += new MouseEventHandler(c.adornerContent_MouseEnter);
|
||||||
|
newAdornerContent.MouseLeave += new MouseEventHandler(c.adornerContent_MouseLeave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the mouse cursor enters the area of the adorner.
|
||||||
|
/// </summary>
|
||||||
|
private void adornerContent_MouseEnter(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
MouseEnterLogic();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the mouse cursor leaves the area of the adorner.
|
||||||
|
/// </summary>
|
||||||
|
private void adornerContent_MouseLeave(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
MouseLeaveLogic();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal method to show or hide the adorner based on the value of IsAdornerVisible.
|
||||||
|
/// </summary>
|
||||||
|
private void ShowOrHideAdornerInternal()
|
||||||
|
{
|
||||||
|
if (IsAdornerVisible)
|
||||||
|
{
|
||||||
|
ShowAdornerInternal();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HideAdornerInternal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a child element in the visual tree that has the specified name.
|
||||||
|
/// Returns null if no child with that name exists.
|
||||||
|
/// </summary>
|
||||||
|
public static FrameworkElement FindNamedChild(FrameworkElement rootElement, string childName)
|
||||||
|
{
|
||||||
|
int numChildren = VisualTreeHelper.GetChildrenCount(rootElement);
|
||||||
|
for (int i = 0; i < numChildren; ++i)
|
||||||
|
{
|
||||||
|
DependencyObject child = VisualTreeHelper.GetChild(rootElement, i);
|
||||||
|
FrameworkElement childElement = child as FrameworkElement;
|
||||||
|
if (childElement != null && childElement.Name == childName)
|
||||||
|
{
|
||||||
|
return childElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameworkElement foundElement = FindNamedChild(childElement, childName);
|
||||||
|
if (foundElement != null)
|
||||||
|
{
|
||||||
|
return foundElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal method to show the adorner.
|
||||||
|
/// </summary>
|
||||||
|
private void ShowAdornerInternal()
|
||||||
|
{
|
||||||
|
if (this.adorner != null)
|
||||||
|
{
|
||||||
|
// Already adorned.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.AdornerContent != null)
|
||||||
|
{
|
||||||
|
if (this.adornerLayer == null)
|
||||||
|
{
|
||||||
|
this.adornerLayer = AdornerLayer.GetAdornerLayer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.adornerLayer != null)
|
||||||
|
{
|
||||||
|
FrameworkElement adornedControl = this; // The control to be adorned defaults to 'this'.
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(this.AdornedTemplatePartName))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// If 'AdornedTemplatePartName' is set to a valid string then search the visual-tree
|
||||||
|
// for a UI element that has the specified part name. If we find it then use it as the
|
||||||
|
// adorned control, otherwise throw an exception.
|
||||||
|
//
|
||||||
|
adornedControl = FindNamedChild(this, this.AdornedTemplatePartName);
|
||||||
|
if (adornedControl == null)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("Failed to find a FrameworkElement in the visual-tree with the part name '" + this.AdornedTemplatePartName + "'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.adorner = new FrameworkElementAdorner(this.AdornerContent, adornedControl,
|
||||||
|
this.HorizontalAdornerPlacement, this.VerticalAdornerPlacement,
|
||||||
|
this.AdornerOffsetX, this.AdornerOffsetY);
|
||||||
|
this.adornerLayer.Add(this.adorner);
|
||||||
|
|
||||||
|
UpdateAdornerDataContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.adornerShowState = AdornerShowState.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal method to hide the adorner.
|
||||||
|
/// </summary>
|
||||||
|
private void HideAdornerInternal()
|
||||||
|
{
|
||||||
|
if (this.adornerLayer == null || this.adorner == null)
|
||||||
|
{
|
||||||
|
// Not already adorned.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stop the timer that might be about to fade out the adorner.
|
||||||
|
//
|
||||||
|
closeAdornerTimer.Stop();
|
||||||
|
this.adornerLayer.Remove(this.adorner);
|
||||||
|
this.adorner.DisconnectChild();
|
||||||
|
|
||||||
|
this.adorner = null;
|
||||||
|
this.adornerLayer = null;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ensure that the state of the adorned control reflects that
|
||||||
|
// the the adorner is no longer.
|
||||||
|
//
|
||||||
|
this.adornerShowState = AdornerShowState.Hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called to build the visual tree.
|
||||||
|
/// </summary>
|
||||||
|
public override void OnApplyTemplate()
|
||||||
|
{
|
||||||
|
base.OnApplyTemplate();
|
||||||
|
|
||||||
|
ShowOrHideAdornerInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the mouse cursor enters the area of the adorned control.
|
||||||
|
/// </summary>
|
||||||
|
protected override void OnMouseEnter(MouseEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnMouseEnter(e);
|
||||||
|
|
||||||
|
MouseEnterLogic();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the mouse cursor leaves the area of the adorned control.
|
||||||
|
/// </summary>
|
||||||
|
protected override void OnMouseLeave(MouseEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnMouseLeave(e);
|
||||||
|
|
||||||
|
MouseLeaveLogic();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shared mouse enter code.
|
||||||
|
/// </summary>
|
||||||
|
private void MouseEnterLogic()
|
||||||
|
{
|
||||||
|
if (!IsMouseOverShowEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeAdornerTimer.Stop();
|
||||||
|
|
||||||
|
FadeInAdorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shared mouse leave code.
|
||||||
|
/// </summary>
|
||||||
|
private void MouseLeaveLogic()
|
||||||
|
{
|
||||||
|
if (!IsMouseOverShowEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeAdornerTimer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the close adorner time-out has ellapsed, the mouse has moved
|
||||||
|
/// away from the adorned control and the adorner and it is time to close the adorner.
|
||||||
|
/// </summary>
|
||||||
|
private void closeAdornerTimer_Tick(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
closeAdornerTimer.Stop();
|
||||||
|
|
||||||
|
FadeOutAdorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the fade in animation has completed.
|
||||||
|
/// </summary>
|
||||||
|
private void fadeInAnimation_Completed(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
adornerShowState = AdornerShowState.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the fade-out animation has completed.
|
||||||
|
/// </summary>
|
||||||
|
private void fadeOutAnimation_Completed(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (adornerShowState == AdornerShowState.FadingOut)
|
||||||
|
{
|
||||||
|
// Still fading out, eg it wasn't aborted.
|
||||||
|
this.HideAdorner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Private/Internal Functions
|
||||||
|
}
|
||||||
|
}
|
||||||
22
VideoBrowser/Controls/AdornedControl/AdornerPlacement.cs
Normal file
22
VideoBrowser/Controls/AdornedControl/AdornerPlacement.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
namespace VideoBrowser.Controls.AdornedControl
|
||||||
|
{
|
||||||
|
#region Enums
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the placement of the adorner in related to the adorned control.
|
||||||
|
/// </summary>
|
||||||
|
public enum AdornerPlacement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the Inside.
|
||||||
|
/// </summary>
|
||||||
|
Inside,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the Outside.
|
||||||
|
/// </summary>
|
||||||
|
Outside
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Enums
|
||||||
|
}
|
||||||
334
VideoBrowser/Controls/AdornedControl/FrameworkElementAdorner.cs
Normal file
334
VideoBrowser/Controls/AdornedControl/FrameworkElementAdorner.cs
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
//
|
||||||
|
// This code based on code available here:
|
||||||
|
//
|
||||||
|
// http://www.codeproject.com/KB/WPF/WPFJoshSmith.aspx
|
||||||
|
//
|
||||||
|
namespace VideoBrowser.Controls.AdornedControl
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
//
|
||||||
|
// This class is an adorner that allows a FrameworkElement derived class to adorn another FrameworkElement.
|
||||||
|
//
|
||||||
|
public class FrameworkElementAdorner : Adorner
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// The framework element that is the adorner.
|
||||||
|
//
|
||||||
|
private FrameworkElement child;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Placement of the child.
|
||||||
|
//
|
||||||
|
private readonly AdornerPlacement horizontalAdornerPlacement = AdornerPlacement.Inside;
|
||||||
|
|
||||||
|
private readonly AdornerPlacement verticalAdornerPlacement = AdornerPlacement.Inside;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Offset of the child.
|
||||||
|
//
|
||||||
|
private readonly double offsetX = 0.0;
|
||||||
|
|
||||||
|
private readonly double offsetY = 0.0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Position of the child (when not set to NaN).
|
||||||
|
//
|
||||||
|
private double positionX = Double.NaN;
|
||||||
|
|
||||||
|
private double positionY = Double.NaN;
|
||||||
|
|
||||||
|
public FrameworkElementAdorner(FrameworkElement adornerChildElement, FrameworkElement adornedElement)
|
||||||
|
: base(adornedElement)
|
||||||
|
{
|
||||||
|
this.child = adornerChildElement;
|
||||||
|
|
||||||
|
base.AddLogicalChild(adornerChildElement);
|
||||||
|
base.AddVisualChild(adornerChildElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameworkElementAdorner(FrameworkElement adornerChildElement, FrameworkElement adornedElement,
|
||||||
|
AdornerPlacement horizontalAdornerPlacement, AdornerPlacement verticalAdornerPlacement,
|
||||||
|
double offsetX, double offsetY)
|
||||||
|
: base(adornedElement)
|
||||||
|
{
|
||||||
|
this.child = adornerChildElement;
|
||||||
|
this.horizontalAdornerPlacement = horizontalAdornerPlacement;
|
||||||
|
this.verticalAdornerPlacement = verticalAdornerPlacement;
|
||||||
|
this.offsetX = offsetX;
|
||||||
|
this.offsetY = offsetY;
|
||||||
|
|
||||||
|
adornedElement.SizeChanged += new SizeChangedEventHandler(adornedElement_SizeChanged);
|
||||||
|
|
||||||
|
base.AddLogicalChild(adornerChildElement);
|
||||||
|
base.AddVisualChild(adornerChildElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the adorned control's size has changed.
|
||||||
|
/// </summary>
|
||||||
|
private void adornedElement_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
|
{
|
||||||
|
InvalidateMeasure();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Position of the child (when not set to NaN).
|
||||||
|
//
|
||||||
|
public double PositionX
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return positionX;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
positionX = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double PositionY
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return positionY;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
positionY = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size MeasureOverride(Size constraint)
|
||||||
|
{
|
||||||
|
this.child.Measure(constraint);
|
||||||
|
return this.child.DesiredSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determine the X coordinate of the child.
|
||||||
|
/// </summary>
|
||||||
|
private double DetermineX()
|
||||||
|
{
|
||||||
|
switch (child.HorizontalAlignment)
|
||||||
|
{
|
||||||
|
case HorizontalAlignment.Left:
|
||||||
|
{
|
||||||
|
if (horizontalAdornerPlacement == AdornerPlacement.Outside)
|
||||||
|
{
|
||||||
|
return -child.DesiredSize.Width + offsetX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return offsetX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case HorizontalAlignment.Right:
|
||||||
|
{
|
||||||
|
if (horizontalAdornerPlacement == AdornerPlacement.Outside)
|
||||||
|
{
|
||||||
|
double adornedWidth = AdornedElement.ActualWidth;
|
||||||
|
return adornedWidth + offsetX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double adornerWidth = this.child.DesiredSize.Width;
|
||||||
|
double adornedWidth = AdornedElement.ActualWidth;
|
||||||
|
double x = adornedWidth - adornerWidth;
|
||||||
|
return x + offsetX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case HorizontalAlignment.Center:
|
||||||
|
{
|
||||||
|
double adornerWidth = this.child.DesiredSize.Width;
|
||||||
|
double adornedWidth = AdornedElement.ActualWidth;
|
||||||
|
double x = (adornedWidth / 2) - (adornerWidth / 2);
|
||||||
|
return x + offsetX;
|
||||||
|
}
|
||||||
|
case HorizontalAlignment.Stretch:
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determine the Y coordinate of the child.
|
||||||
|
/// </summary>
|
||||||
|
private double DetermineY()
|
||||||
|
{
|
||||||
|
switch (child.VerticalAlignment)
|
||||||
|
{
|
||||||
|
case VerticalAlignment.Top:
|
||||||
|
{
|
||||||
|
if (verticalAdornerPlacement == AdornerPlacement.Outside)
|
||||||
|
{
|
||||||
|
return -child.DesiredSize.Height + offsetY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return offsetY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case VerticalAlignment.Bottom:
|
||||||
|
{
|
||||||
|
if (verticalAdornerPlacement == AdornerPlacement.Outside)
|
||||||
|
{
|
||||||
|
double adornedHeight = AdornedElement.ActualHeight;
|
||||||
|
return adornedHeight + offsetY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double adornerHeight = this.child.DesiredSize.Height;
|
||||||
|
double adornedHeight = AdornedElement.ActualHeight;
|
||||||
|
double x = adornedHeight - adornerHeight;
|
||||||
|
return x + offsetY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case VerticalAlignment.Center:
|
||||||
|
{
|
||||||
|
double adornerHeight = this.child.DesiredSize.Height;
|
||||||
|
double adornedHeight = AdornedElement.ActualHeight;
|
||||||
|
double x = (adornedHeight / 2) - (adornerHeight / 2);
|
||||||
|
return x + offsetY;
|
||||||
|
}
|
||||||
|
case VerticalAlignment.Stretch:
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determine the width of the child.
|
||||||
|
/// </summary>
|
||||||
|
private double DetermineWidth()
|
||||||
|
{
|
||||||
|
if (!Double.IsNaN(PositionX))
|
||||||
|
{
|
||||||
|
return this.child.DesiredSize.Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (child.HorizontalAlignment)
|
||||||
|
{
|
||||||
|
case HorizontalAlignment.Left:
|
||||||
|
{
|
||||||
|
return this.child.DesiredSize.Width;
|
||||||
|
}
|
||||||
|
case HorizontalAlignment.Right:
|
||||||
|
{
|
||||||
|
return this.child.DesiredSize.Width;
|
||||||
|
}
|
||||||
|
case HorizontalAlignment.Center:
|
||||||
|
{
|
||||||
|
return this.child.DesiredSize.Width;
|
||||||
|
}
|
||||||
|
case HorizontalAlignment.Stretch:
|
||||||
|
{
|
||||||
|
return AdornedElement.ActualWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determine the height of the child.
|
||||||
|
/// </summary>
|
||||||
|
private double DetermineHeight()
|
||||||
|
{
|
||||||
|
if (!Double.IsNaN(PositionY))
|
||||||
|
{
|
||||||
|
return this.child.DesiredSize.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (child.VerticalAlignment)
|
||||||
|
{
|
||||||
|
case VerticalAlignment.Top:
|
||||||
|
{
|
||||||
|
return this.child.DesiredSize.Height;
|
||||||
|
}
|
||||||
|
case VerticalAlignment.Bottom:
|
||||||
|
{
|
||||||
|
return this.child.DesiredSize.Height;
|
||||||
|
}
|
||||||
|
case VerticalAlignment.Center:
|
||||||
|
{
|
||||||
|
return this.child.DesiredSize.Height;
|
||||||
|
}
|
||||||
|
case VerticalAlignment.Stretch:
|
||||||
|
{
|
||||||
|
return AdornedElement.ActualHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size ArrangeOverride(Size finalSize)
|
||||||
|
{
|
||||||
|
double x = PositionX;
|
||||||
|
if (Double.IsNaN(x))
|
||||||
|
{
|
||||||
|
x = DetermineX();
|
||||||
|
}
|
||||||
|
double y = PositionY;
|
||||||
|
if (Double.IsNaN(y))
|
||||||
|
{
|
||||||
|
y = DetermineY();
|
||||||
|
}
|
||||||
|
double adornerWidth = DetermineWidth();
|
||||||
|
double adornerHeight = DetermineHeight();
|
||||||
|
this.child.Arrange(new Rect(x, y, adornerWidth, adornerHeight));
|
||||||
|
return finalSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Int32 VisualChildrenCount
|
||||||
|
{
|
||||||
|
get { return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Visual GetVisualChild(Int32 index)
|
||||||
|
{
|
||||||
|
return this.child;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerator LogicalChildren
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ArrayList list = new ArrayList();
|
||||||
|
list.Add(this.child);
|
||||||
|
return list.GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disconnect the child element from the visual tree so that it may be reused later.
|
||||||
|
/// </summary>
|
||||||
|
public void DisconnectChild()
|
||||||
|
{
|
||||||
|
base.RemoveLogicalChild(child);
|
||||||
|
base.RemoveVisualChild(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Override AdornedElement from base class for less type-checking.
|
||||||
|
/// </summary>
|
||||||
|
public new FrameworkElement AdornedElement
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (FrameworkElement)base.AdornedElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
184
VideoBrowser/Controls/AirspaceFixer/AirspacePanel.cs
Normal file
184
VideoBrowser/Controls/AirspaceFixer/AirspacePanel.cs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
namespace VideoBrowser.Controls.AirspaceFixer
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="AirspacePanel" />
|
||||||
|
/// </summary>
|
||||||
|
public class AirspacePanel : ContentControl
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
public static readonly DependencyProperty FixAirspaceProperty =
|
||||||
|
DependencyProperty.Register(nameof(FixAirspace),
|
||||||
|
typeof(bool),
|
||||||
|
typeof(AirspacePanel),
|
||||||
|
new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnFixAirspaceChanged)));
|
||||||
|
|
||||||
|
private ContentControl _airspaceContent;
|
||||||
|
|
||||||
|
private Image _airspaceScreenshot;
|
||||||
|
|
||||||
|
private float _scalingFactor;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AirspacePanel"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public AirspacePanel()
|
||||||
|
{
|
||||||
|
Loaded += (_, __) => GetScalingFactor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes static members of the <see cref="AirspacePanel"/> class.
|
||||||
|
/// </summary>
|
||||||
|
static AirspacePanel()
|
||||||
|
{
|
||||||
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(AirspacePanel), new FrameworkPropertyMetadata(typeof(AirspacePanel)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether FixAirspace
|
||||||
|
/// </summary>
|
||||||
|
public bool FixAirspace
|
||||||
|
{
|
||||||
|
get { return (bool)GetValue(FixAirspaceProperty); }
|
||||||
|
set { SetValue(FixAirspaceProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetImageSourceFromBitmap
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bitmap">The bitmap<see cref="System.Drawing.Bitmap"/></param>
|
||||||
|
/// <returns>The <see cref="ImageSource"/></returns>
|
||||||
|
public ImageSource GetImageSourceFromBitmap(System.Drawing.Bitmap bitmap)
|
||||||
|
{
|
||||||
|
using (var memory = new MemoryStream())
|
||||||
|
{
|
||||||
|
bitmap.Save(memory, ImageFormat.Bmp);
|
||||||
|
memory.Position = 0;
|
||||||
|
var bitmapImage = new BitmapImage();
|
||||||
|
bitmapImage.BeginInit();
|
||||||
|
bitmapImage.StreamSource = memory;
|
||||||
|
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
||||||
|
bitmapImage.EndInit();
|
||||||
|
return bitmapImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnApplyTemplate
|
||||||
|
/// </summary>
|
||||||
|
public override void OnApplyTemplate()
|
||||||
|
{
|
||||||
|
base.OnApplyTemplate();
|
||||||
|
|
||||||
|
_airspaceContent = GetTemplateChild("PART_AirspaceContent") as ContentControl;
|
||||||
|
_airspaceScreenshot = GetTemplateChild("PART_AirspaceScreenshot") as Image;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/5977445/how-to-get-windows-display-settings
|
||||||
|
/// <summary>
|
||||||
|
/// The GetDeviceCaps
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hdc">The hdc<see cref="IntPtr"/></param>
|
||||||
|
/// <param name="nIndex">The nIndex<see cref="int"/></param>
|
||||||
|
/// <returns>The <see cref="int"/></returns>
|
||||||
|
[DllImport("gdi32.dll")]
|
||||||
|
internal static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnFixAirspaceChanged
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="d">The d<see cref="DependencyObject"/></param>
|
||||||
|
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/></param>
|
||||||
|
private static async void OnFixAirspaceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var panel = d as AirspacePanel;
|
||||||
|
if (panel == null || panel.ActualWidth == 0 || panel.ActualHeight == 0 || PresentationSource.FromVisual(panel) == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((bool)e.NewValue)
|
||||||
|
{
|
||||||
|
panel.CreateScreenshotFromContent();
|
||||||
|
panel._airspaceScreenshot.Visibility = Visibility.Visible;
|
||||||
|
await Task.Delay(300);
|
||||||
|
panel._airspaceContent.Visibility = Visibility.Hidden;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
panel._airspaceContent.Visibility = Visibility.Visible;
|
||||||
|
panel._airspaceScreenshot.Visibility = Visibility.Hidden;
|
||||||
|
panel._airspaceScreenshot.Source = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CreateScreenshotFromContent
|
||||||
|
/// </summary>
|
||||||
|
private void CreateScreenshotFromContent()
|
||||||
|
{
|
||||||
|
var source = PresentationSource.FromVisual(this);
|
||||||
|
|
||||||
|
var scalingX = source.CompositionTarget.TransformToDevice.M11;
|
||||||
|
var scalingY = source.CompositionTarget.TransformToDevice.M22;
|
||||||
|
|
||||||
|
var upperLeftPoint = _airspaceContent.PointToScreen(new Point(0, 0));
|
||||||
|
var bounds = new System.Drawing.Rectangle((int)(upperLeftPoint.X * _scalingFactor),
|
||||||
|
(int)(upperLeftPoint.Y * _scalingFactor),
|
||||||
|
(int)(_airspaceContent.RenderSize.Width * scalingX),
|
||||||
|
(int)(_airspaceContent.RenderSize.Height * scalingY));
|
||||||
|
|
||||||
|
using (var bitmap = new System.Drawing.Bitmap(bounds.Width, bounds.Height))
|
||||||
|
{
|
||||||
|
using (var g = System.Drawing.Graphics.FromImage(bitmap))
|
||||||
|
{
|
||||||
|
g.CopyFromScreen(new System.Drawing.Point(bounds.Left, bounds.Top),
|
||||||
|
System.Drawing.Point.Empty,
|
||||||
|
new System.Drawing.Size(bounds.Width, bounds.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
_airspaceScreenshot.Source = GetImageSourceFromBitmap(bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetScalingFactor
|
||||||
|
/// </summary>
|
||||||
|
private void GetScalingFactor()
|
||||||
|
{
|
||||||
|
var g = System.Drawing.Graphics.FromHwnd(IntPtr.Zero);
|
||||||
|
var desktop = g.GetHdc();
|
||||||
|
var LogicalScreenHeight = GetDeviceCaps(desktop, 10);
|
||||||
|
var PhysicalScreenHeight = GetDeviceCaps(desktop, 117);
|
||||||
|
|
||||||
|
var ScreenScalingFactor = PhysicalScreenHeight / (float)LogicalScreenHeight;
|
||||||
|
|
||||||
|
_scalingFactor = ScreenScalingFactor; // 1.25 = 125%
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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:VideoBrowser.Controls.AirspaceFixer">
|
||||||
|
<Style TargetType="{x:Type local:AirspacePanel}">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type local:AirspacePanel}">
|
||||||
|
<Grid HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">
|
||||||
|
<Image x:Name="PART_AirspaceScreenshot" Visibility="Hidden" />
|
||||||
|
<ContentControl x:Name="PART_AirspaceContent" Content="{TemplateBinding Content}" />
|
||||||
|
</Grid>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
||||||
8
VideoBrowser/Controls/AirspaceFixer/Themes/Generic.xaml
Normal file
8
VideoBrowser/Controls/AirspaceFixer/Themes/Generic.xaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<ResourceDictionary
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:VideoBrowser.Controls.AirspaceFixer.Themes">
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="/AirspaceFixer;component/Themes/AirspacePanel.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
100
VideoBrowser/Controls/CefSharpBrowser/AddInButton.cs
Normal file
100
VideoBrowser/Controls/CefSharpBrowser/AddInButton.cs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser
|
||||||
|
{
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="AddInButton" />.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class AddInButton : NotifyPropertyChanged
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private Geometry _icon;
|
||||||
|
|
||||||
|
private bool _isEnabled = true;
|
||||||
|
|
||||||
|
private string _toolTip;
|
||||||
|
|
||||||
|
private bool isVisible;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AddInButton"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name<see cref="string"/>.</param>
|
||||||
|
protected AddInButton(string name = null)
|
||||||
|
{
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
name = this.GetType().Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Name = name;
|
||||||
|
this.Command = new RelayCommand(this.OnExecute, $"{this.Name} add in is executed");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Command.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand Command { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Icon.
|
||||||
|
/// </summary>
|
||||||
|
public Geometry Icon { get => _icon; set => this.Set(this.PropertyChangedHandler, ref _icon, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsEnabled.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEnabled { get => _isEnabled; set => this.Set(this.PropertyChangedHandler, ref _isEnabled, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsVisible.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsVisible { get => isVisible; set => this.Set(this.PropertyChangedHandler, ref isVisible, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the ToolTip.
|
||||||
|
/// </summary>
|
||||||
|
public string ToolTip { get => _toolTip; set => this.Set(this.PropertyChangedHandler, ref _toolTip, value); }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Execute.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="viewModel">The viewModel<see cref="WebBrowserTabControlViewModel"/>.</param>
|
||||||
|
protected abstract void Execute(WebBrowserTabControlViewModel viewModel);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnExecute.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnExecute(object obj)
|
||||||
|
{
|
||||||
|
var viewModel = obj as WebBrowserTabControlViewModel;
|
||||||
|
this.Execute(viewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.AddIns
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Models;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Resources;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BookmarkAddIn" />.
|
||||||
|
/// </summary>
|
||||||
|
public class BookmarkAddIn : AddInButton
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private string url;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BookmarkAddIn"/> class.
|
||||||
|
/// </summary>
|
||||||
|
internal BookmarkAddIn()
|
||||||
|
{
|
||||||
|
this.Icon = BrowserIcons.StarWF;
|
||||||
|
this.ToolTip = "Bookmark this page";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the BookmarkModels.
|
||||||
|
/// </summary>
|
||||||
|
public IList<BookmarkModel> BookmarkModels { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Url.
|
||||||
|
/// </summary>
|
||||||
|
public string Url
|
||||||
|
{
|
||||||
|
get => url;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!this.Set(this.PropertyChangedHandler, ref url, value))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.IsVisible = !string.IsNullOrEmpty(this.Url);
|
||||||
|
var bookmarkExist = false;
|
||||||
|
if (this.BookmarkModels != null)
|
||||||
|
{
|
||||||
|
foreach (var bookmark in this.BookmarkModels)
|
||||||
|
{
|
||||||
|
if (bookmark.Url == this.Url)
|
||||||
|
{
|
||||||
|
bookmarkExist = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Icon = bookmarkExist ? BrowserIcons.Star : BrowserIcons.StarWF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Execute.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="viewModel">The viewModel<see cref="WebBrowserTabControlViewModel"/>.</param>
|
||||||
|
protected override void Execute(WebBrowserTabControlViewModel viewModel)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.AddIns
|
||||||
|
{
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Resources;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="IsSecureAddIn" />.
|
||||||
|
/// </summary>
|
||||||
|
public class IsSecureAddIn : AddInButton
|
||||||
|
{
|
||||||
|
private string _url;
|
||||||
|
|
||||||
|
public IsSecureAddIn()
|
||||||
|
{
|
||||||
|
this.Icon = BrowserIcons.Lock;
|
||||||
|
this.ToolTip = "The connection is secure";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Url.
|
||||||
|
/// </summary>
|
||||||
|
public string Url
|
||||||
|
{
|
||||||
|
get => _url;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!this.Set(this.PropertyChangedHandler, ref _url, value) || string.IsNullOrEmpty(this.Url))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.IsVisible = this.Url.Contains("https://");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Execute.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="viewModel">The viewModel<see cref="WebBrowserTabControlViewModel"/>.</param>
|
||||||
|
protected override void Execute(WebBrowserTabControlViewModel viewModel)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
48
VideoBrowser/Controls/CefSharpBrowser/BrowserSettings.cs
Normal file
48
VideoBrowser/Controls/CefSharpBrowser/BrowserSettings.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BrowserSettings" />.
|
||||||
|
/// </summary>
|
||||||
|
public class BrowserSettings
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BrowserSettings"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public BrowserSettings()
|
||||||
|
{
|
||||||
|
this.BookmarkModels = new List<BookmarkModel>();
|
||||||
|
this.TabSettingModels = new List<TabSettingsModel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the BookmarkModels.
|
||||||
|
/// </summary>
|
||||||
|
public IList<BookmarkModel> BookmarkModels { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the SelectedTabSettingIndex.
|
||||||
|
/// </summary>
|
||||||
|
public int SelectedTabSettingIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the TabSettingModels.
|
||||||
|
/// </summary>
|
||||||
|
public IList<TabSettingsModel> TabSettingModels { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Version.
|
||||||
|
/// </summary>
|
||||||
|
public string Version { get; set; } = "1.0";
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
}
|
||||||
|
}
|
||||||
26
VideoBrowser/Controls/CefSharpBrowser/CefSharpBrowser.xaml
Normal file
26
VideoBrowser/Controls/CefSharpBrowser/CefSharpBrowser.xaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<Grid
|
||||||
|
x:Class="VideoBrowser.Controls.CefSharpBrowser.CefSharpBrowser"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:viewmodels="clr-namespace:VideoBrowser.Controls.CefSharpBrowser.ViewModels"
|
||||||
|
xmlns:wpf="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
|
||||||
|
x:Name="WebBrowserRoot"
|
||||||
|
d:DataContext="{d:DesignInstance viewmodels:VideoBrowserViewModel}"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Grid.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="../AirspaceFixer/Themes/AirspacePanel.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Grid.Resources>
|
||||||
|
<wpf:ChromiumWebBrowser
|
||||||
|
x:Name="ChromiumWebBrowser"
|
||||||
|
Address="{Binding ElementName=WebBrowserRoot, Path=Url, Mode=TwoWay}"
|
||||||
|
AllowDrop="True"
|
||||||
|
RenderOptions.BitmapScalingMode="Linear" />
|
||||||
|
</Grid>
|
||||||
300
VideoBrowser/Controls/CefSharpBrowser/CefSharpBrowser.xaml.cs
Normal file
300
VideoBrowser/Controls/CefSharpBrowser/CefSharpBrowser.xaml.cs
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using CefSharp.Wpf;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Handlers;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Helpers;
|
||||||
|
using VideoBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for CefSharpBrowser.xaml.
|
||||||
|
/// </summary>
|
||||||
|
public partial class CefSharpBrowser
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
public static readonly DependencyProperty BackwardCommandProperty =
|
||||||
|
DependencyProperty.Register(nameof(BackwardCommand), typeof(ICommand), typeof(CefSharpBrowser), new PropertyMetadata(null));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ForwardCommandProperty =
|
||||||
|
DependencyProperty.Register(nameof(ForwardCommand), typeof(ICommand), typeof(CefSharpBrowser), new PropertyMetadata(null));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty IsAirspaceVisibleProperty =
|
||||||
|
DependencyProperty.Register(nameof(IsAirspaceVisible), typeof(bool), typeof(CefSharpBrowser), new PropertyMetadata(false));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty IsFullScreenCommandProperty =
|
||||||
|
DependencyProperty.Register(nameof(IsFullScreenCommand), typeof(ICommand), typeof(CefSharpBrowser), new PropertyMetadata(null, OnIsFullScreenCommandChanged));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ReloadCommandProperty =
|
||||||
|
DependencyProperty.Register(nameof(ReloadCommand), typeof(ICommand), typeof(CefSharpBrowser), new PropertyMetadata(null));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty TitleProperty =
|
||||||
|
DependencyProperty.Register(nameof(Title), typeof(string), typeof(CefSharpBrowser), new FrameworkPropertyMetadata("Home", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty UrlProperty =
|
||||||
|
DependencyProperty.Register(nameof(Url), typeof(string), typeof(CefSharpBrowser), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnUrlChanged));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty WebBrowserProperty =
|
||||||
|
DependencyProperty.Register(nameof(WebBrowser), typeof(IWebBrowser), typeof(CefSharpBrowser), new PropertyMetadata(null));
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CefSharpBrowser"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public CefSharpBrowser()
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
this.CefDisplayHandler = new CefDisplayHandler();
|
||||||
|
this.InitializeComponent();
|
||||||
|
this.ChromiumWebBrowser.TitleChanged += this.OnChromiumWebBrowser_TitleChanged;
|
||||||
|
this.Loaded += this.OnLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the BackwardCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand BackwardCommand
|
||||||
|
{
|
||||||
|
get { return (ICommand)GetValue(BackwardCommandProperty); }
|
||||||
|
set { SetValue(BackwardCommandProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the CefSettings.
|
||||||
|
/// </summary>
|
||||||
|
public CefSettings CefSettings { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the ForwardCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand ForwardCommand
|
||||||
|
{
|
||||||
|
get { return (ICommand)GetValue(ForwardCommandProperty); }
|
||||||
|
set { SetValue(ForwardCommandProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsAirspaceVisible.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAirspaceVisible
|
||||||
|
{
|
||||||
|
get { return (bool)GetValue(IsAirspaceVisibleProperty); }
|
||||||
|
set { SetValue(IsAirspaceVisibleProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the IsFullScreenCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand IsFullScreenCommand
|
||||||
|
{
|
||||||
|
get { return (ICommand)GetValue(IsFullScreenCommandProperty); }
|
||||||
|
set { SetValue(IsFullScreenCommandProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the ReloadCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand ReloadCommand
|
||||||
|
{
|
||||||
|
get { return (ICommand)GetValue(ReloadCommandProperty); }
|
||||||
|
set { SetValue(ReloadCommandProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Title.
|
||||||
|
/// </summary>
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(TitleProperty); }
|
||||||
|
set { SetValue(TitleProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Url.
|
||||||
|
/// </summary>
|
||||||
|
public string Url
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(UrlProperty); }
|
||||||
|
set { SetValue(UrlProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the WebBrowser.
|
||||||
|
/// </summary>
|
||||||
|
public IWebBrowser WebBrowser
|
||||||
|
{
|
||||||
|
get { return (IWebBrowser)this.GetValue(WebBrowserProperty); }
|
||||||
|
set { this.SetValue(WebBrowserProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether CanBackward.
|
||||||
|
/// </summary>
|
||||||
|
private bool CanBackward { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether CanForward.
|
||||||
|
/// </summary>
|
||||||
|
private bool CanForward { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether CanReload.
|
||||||
|
/// </summary>
|
||||||
|
private bool CanReload { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the CefDisplayHandler.
|
||||||
|
/// </summary>
|
||||||
|
private CefDisplayHandler CefDisplayHandler { get; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Initialize.
|
||||||
|
/// </summary>
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
if (!Cef.IsInitialized)
|
||||||
|
{
|
||||||
|
System.AppContext.SetSwitch("Switch.System.Windows.Input.Stylus.EnablePointerSupport", true);
|
||||||
|
const bool multiThreadedMessageLoop = true;
|
||||||
|
var browserProcessHandler = new BrowserProcessHandler();
|
||||||
|
var settings = new CefSettings
|
||||||
|
{
|
||||||
|
//UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0",
|
||||||
|
MultiThreadedMessageLoop = multiThreadedMessageLoop,
|
||||||
|
ExternalMessagePump = !multiThreadedMessageLoop
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.PersistSessionCookies = true;
|
||||||
|
settings.SetOffScreenRenderingBestPerformanceArgs();
|
||||||
|
settings.CefCommandLineArgs.Remove("disable-gpu-compositing");
|
||||||
|
CefConfig.Init(settings, browserProcessHandler: browserProcessHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnIsFullScreenCommandChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="d">The d<see cref="DependencyObject"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
|
||||||
|
private static void OnIsFullScreenCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var browser = (CefSharpBrowser)d;
|
||||||
|
var isFullScreenCommand = (ICommand)e.NewValue;
|
||||||
|
browser.CefDisplayHandler.IsFullScreenCommand = isFullScreenCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnUrlChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="d">The d<see cref="DependencyObject"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
|
||||||
|
private static void OnUrlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
UIThreadHelper.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
CommandManager.InvalidateRequerySuggested();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnBackward.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnBackward(object obj)
|
||||||
|
{
|
||||||
|
if (this.WebBrowser.CanGoBack)
|
||||||
|
{
|
||||||
|
this.WebBrowser.Back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnChromiumWebBrowser_TitleChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender<see cref="object"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
|
||||||
|
private void OnChromiumWebBrowser_TitleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
UIThreadHelper.InvokeAsync(() => this.Title = (string)e.NewValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnForward.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnForward(object obj)
|
||||||
|
{
|
||||||
|
if (this.WebBrowser.CanGoForward)
|
||||||
|
{
|
||||||
|
this.WebBrowser.Forward();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnLoaded.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender<see cref="object"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="RoutedEventArgs"/>.</param>
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.Loaded -= this.OnLoaded;
|
||||||
|
this.WebBrowser = this.ChromiumWebBrowser;
|
||||||
|
this.WebBrowser.LoadingStateChanged += OnWebBrowser_LoadingStateChanged;
|
||||||
|
this.WebBrowser.LoadError += OnWebBrowser_LoadError;
|
||||||
|
this.WebBrowser.DisplayHandler = this.CefDisplayHandler;
|
||||||
|
this.WebBrowser.KeyboardHandler = new CefKeyboardHandler(this.ChromiumWebBrowser);
|
||||||
|
this.BackwardCommand = new RelayCommand(this.OnBackward, "Backward", (o) => this.CanBackward);
|
||||||
|
this.ForwardCommand = new RelayCommand(this.OnForward, "Forward", (o) => this.CanForward);
|
||||||
|
this.ReloadCommand = new RelayCommand(this.OnReload, "Reload", (o) => this.CanReload);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnReload.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnReload(object obj)
|
||||||
|
{
|
||||||
|
this.WebBrowser.Reload(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnWebBrowser_LoadError.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender<see cref="object"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="LoadErrorEventArgs"/>.</param>
|
||||||
|
private void OnWebBrowser_LoadError(object sender, LoadErrorEventArgs e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnWebBrowser_LoadingStateChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender<see cref="object"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="LoadingStateChangedEventArgs"/>.</param>
|
||||||
|
private void OnWebBrowser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e)
|
||||||
|
{
|
||||||
|
UIThreadHelper.Invoke(() =>
|
||||||
|
{
|
||||||
|
this.CanBackward = e.CanGoBack;
|
||||||
|
this.CanForward = e.CanGoForward;
|
||||||
|
this.CanReload = e.CanReload;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
144
VideoBrowser/Controls/CefSharpBrowser/CefWindowData.cs
Normal file
144
VideoBrowser/Controls/CefSharpBrowser/CefWindowData.cs
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser
|
||||||
|
{
|
||||||
|
using MahApps.Metro.Controls;
|
||||||
|
using MahApps.Metro.Controls.Dialogs;
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Handlers;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="CefWindowData" />.
|
||||||
|
/// </summary>
|
||||||
|
public class CefWindowData : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private bool _isAirspaceVisible;
|
||||||
|
|
||||||
|
private bool _isFullScreen;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CefWindowData"/> class.
|
||||||
|
/// </summary>
|
||||||
|
internal CefWindowData()
|
||||||
|
{
|
||||||
|
this.IsFullScreenCommand = new RelayCommand(this.OnIsFullScreen);
|
||||||
|
this.CefContextMenuHandler = new CefContextMenuHandler();
|
||||||
|
this.CefRequestHandler = new CefRequestHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the PropertyChanged.
|
||||||
|
/// </summary>
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
#endregion Events
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the CefContextMenuHandler.
|
||||||
|
/// </summary>
|
||||||
|
public CefContextMenuHandler CefContextMenuHandler { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the CefRequestHandler.
|
||||||
|
/// </summary>
|
||||||
|
public CefRequestHandler CefRequestHandler { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsAirspaceVisible.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAirspaceVisible
|
||||||
|
{
|
||||||
|
get => this._isAirspaceVisible;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (this.IsMessageBoxVisible)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Set(this.PropertyChanged, ref this._isAirspaceVisible, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsFullScreen.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsFullScreen { get => _isFullScreen; set => this.Set(this.PropertyChanged, ref _isFullScreen, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the IsFullScreenCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand IsFullScreenCommand { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether IsMessageBoxVisible.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsMessageBoxVisible { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the MainWindow.
|
||||||
|
/// </summary>
|
||||||
|
public MetroWindow MainWindow { get; internal set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ShowMessage.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="title">The title<see cref="string"/>.</param>
|
||||||
|
/// <param name="message">The message<see cref="string"/>.</param>
|
||||||
|
/// <param name="style">The style<see cref="MessageDialogStyle"/>.</param>
|
||||||
|
/// <returns>The <see cref="Task{MessageDialogResult}"/>.</returns>
|
||||||
|
internal async Task<MessageDialogResult> ShowMessageAsync(string title, string message, MessageDialogStyle style = MessageDialogStyle.Affirmative)
|
||||||
|
{
|
||||||
|
var currentAirspaceVisible = this.IsAirspaceVisible;
|
||||||
|
this.IsAirspaceVisible = true;
|
||||||
|
this.IsMessageBoxVisible = true;
|
||||||
|
var dispatcher = this.MainWindow.Dispatcher;
|
||||||
|
Task<MessageDialogResult> result = null;
|
||||||
|
if (dispatcher.CheckAccess())
|
||||||
|
{
|
||||||
|
result = this.MainWindow.ShowMessageAsync(title, message, style);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await dispatcher.BeginInvoke((Action)(() => result = this.MainWindow.ShowMessageAsync(title, message, style)));
|
||||||
|
}
|
||||||
|
|
||||||
|
await result;
|
||||||
|
|
||||||
|
this.IsMessageBoxVisible = false;
|
||||||
|
this.IsAirspaceVisible = false;
|
||||||
|
|
||||||
|
return result.Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnIsFullScreen.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnIsFullScreen(object obj)
|
||||||
|
{
|
||||||
|
this.IsFullScreen = (bool)obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Converters
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="StringToImageConverter" />.
|
||||||
|
/// </summary>
|
||||||
|
public class StringToImageConverter : IValueConverter
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Instance.
|
||||||
|
/// </summary>
|
||||||
|
public static StringToImageConverter Instance { get; } = new StringToImageConverter();
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Convert.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value<see cref="object"/>.</param>
|
||||||
|
/// <param name="targetType">The targetType<see cref="Type"/>.</param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/>.</param>
|
||||||
|
/// <param name="culture">The culture<see cref="CultureInfo"/>.</param>
|
||||||
|
/// <returns>The <see cref="object"/>.</returns>
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (!(value is string imageString) || string.IsNullOrEmpty(imageString))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageString.IsImageUrl())
|
||||||
|
{
|
||||||
|
return imageString;
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageSource = imageString.FindIconForFilename(true);
|
||||||
|
return imageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ConvertBack.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value<see cref="object"/>.</param>
|
||||||
|
/// <param name="targetType">The targetType<see cref="Type"/>.</param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/>.</param>
|
||||||
|
/// <param name="culture">The culture<see cref="CultureInfo"/>.</param>
|
||||||
|
/// <returns>The <see cref="object"/>.</returns>
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="CreateTabAddInButton" />.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class CreateTabAddInButton : AddInButton
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CreateTabAddInButton"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="title">The title<see cref="string"/>.</param>
|
||||||
|
/// <param name="icon">The icon<see cref="Geometry"/>.</param>
|
||||||
|
/// <param name="name">The name<see cref="string"/>.</param>
|
||||||
|
public CreateTabAddInButton(string title, Geometry icon, string name = null) : base(name)
|
||||||
|
{
|
||||||
|
this.Title = title;
|
||||||
|
this.Icon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Guid.
|
||||||
|
/// </summary>
|
||||||
|
public Guid Guid { get; } = Guid.NewGuid();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Title.
|
||||||
|
/// </summary>
|
||||||
|
public string Title { get; set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CreateView.
|
||||||
|
/// This method is already in UI Thread.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="UIElement"/>.</returns>
|
||||||
|
protected abstract UIElement CreateView();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Execute.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="viewModel">The viewModel<see cref="WebBrowserTabControlViewModel"/>.</param>
|
||||||
|
protected override void Execute(WebBrowserTabControlViewModel viewModel)
|
||||||
|
{
|
||||||
|
if (viewModel.IsTabItemExist(this.Guid))
|
||||||
|
{
|
||||||
|
viewModel.SetActiveTab(this.Guid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIThreadHelper.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
var view = this.CreateView();
|
||||||
|
var tab = new TabItem(this.Guid)
|
||||||
|
{
|
||||||
|
Content = view,
|
||||||
|
Icon = this.Icon,
|
||||||
|
Title = this.Title
|
||||||
|
};
|
||||||
|
|
||||||
|
viewModel.AddTab(tab);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
117
VideoBrowser/Controls/CefSharpBrowser/GlobalBrowserData.cs
Normal file
117
VideoBrowser/Controls/CefSharpBrowser/GlobalBrowserData.cs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Handlers;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Models;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
using VideoBrowser.ViewModels;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="GlobalBrowserData" />.
|
||||||
|
/// All singleton instances are saved here.
|
||||||
|
/// </summary>
|
||||||
|
public class GlobalBrowserData : IDisposable
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GlobalBrowserData"/> class.
|
||||||
|
/// </summary>
|
||||||
|
internal GlobalBrowserData()
|
||||||
|
{
|
||||||
|
this.InterTabClient = new InterTabClient(this);
|
||||||
|
this.Settings = new SettingsViewModel();
|
||||||
|
this.Settings.PropertyChanged += this.OnSettings_PropertyChanged;
|
||||||
|
this.DownloadHandler = new DownloadHandler(this.DownloadItemModels) { DownloadPath = this.Settings.OutputFolder };
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the AddInButtons.
|
||||||
|
/// </summary>
|
||||||
|
public ICollection<AddInButton> AddInButtons { get; } = new ObservableCollection<AddInButton>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the BrowserSettings.
|
||||||
|
/// </summary>
|
||||||
|
public BrowserSettings BrowserSettings => this.Settings.BrowserSettings;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the DownloadHandler.
|
||||||
|
/// </summary>
|
||||||
|
public DownloadHandler DownloadHandler { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the DownloadItemModels.
|
||||||
|
/// </summary>
|
||||||
|
public ObservableCollection<DownloadItemModel> DownloadItemModels { get; } = new ObservableCollection<DownloadItemModel>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the InterTabClient.
|
||||||
|
/// </summary>
|
||||||
|
public InterTabClient InterTabClient { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Settings.
|
||||||
|
/// </summary>
|
||||||
|
public SettingsViewModel Settings { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsSettingsLoaded.
|
||||||
|
/// </summary>
|
||||||
|
internal bool IsSettingsLoaded { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the WindowViewModels.
|
||||||
|
/// </summary>
|
||||||
|
internal IList<MainWindowViewModel> WindowViewModels { get; } = new List<MainWindowViewModel>();
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Dispose.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.Settings.PropertyChanged -= this.OnSettings_PropertyChanged;
|
||||||
|
this.DownloadHandler.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetAddInButton.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="addInType">The addInType<see cref="Type"/>.</param>
|
||||||
|
/// <returns>The <see cref="AddInButton"/>.</returns>
|
||||||
|
public AddInButton GetAddInButton(Type addInType)
|
||||||
|
{
|
||||||
|
var addIn = this.AddInButtons.FirstOrDefault(o => o.GetType() == addInType);
|
||||||
|
return addIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnSettings_PropertyChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender<see cref="object"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="PropertyChangedEventArgs"/>.</param>
|
||||||
|
private void OnSettings_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.IsMatch(nameof(this.Settings.OutputFolder)) && Directory.Exists(this.Settings.OutputFolder))
|
||||||
|
{
|
||||||
|
this.DownloadHandler.DownloadPath = this.Settings.OutputFolder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,373 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Handlers
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using CefSharp.Wpf;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="CefContextMenuHandler" />.
|
||||||
|
/// </summary>
|
||||||
|
public class CefContextMenuHandler : IContextMenuHandler
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
private const CefMenuCommand CopyLinkAdressId = (CefMenuCommand)10000;
|
||||||
|
|
||||||
|
private const CefMenuCommand OpenImageInNewTabId = (CefMenuCommand)10001;
|
||||||
|
|
||||||
|
private const CefMenuCommand OpenInNewTabId = (CefMenuCommand)10002;
|
||||||
|
|
||||||
|
private const CefMenuCommand OpenInNewWindowId = (CefMenuCommand)10003;
|
||||||
|
|
||||||
|
private const CefMenuCommand SearchInWebsiteId = (CefMenuCommand)10004;
|
||||||
|
|
||||||
|
#endregion Constants
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the OpenInNewTabAction.
|
||||||
|
/// </summary>
|
||||||
|
public Action<string> OpenInNewTabAction { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the OpenInNewWindowAction.
|
||||||
|
/// </summary>
|
||||||
|
public Action<string> OpenInNewWindowAction { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the SearchEngineQuery.
|
||||||
|
/// </summary>
|
||||||
|
public string SearchEngineQuery { get; set; } = "https://www.youtube.com/results?search_query=";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the CopyLinkAddress.
|
||||||
|
/// </summary>
|
||||||
|
private static (CefMenuCommand Id, string Text) CopyLinkAddress { get; } = (CopyLinkAdressId, "Copy link address");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the OpenImageInNewTab.
|
||||||
|
/// </summary>
|
||||||
|
private static (CefMenuCommand Id, string Text) OpenImageInNewTab { get; } = (OpenImageInNewTabId, "Open image in new tab");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the OpenInNewTab.
|
||||||
|
/// </summary>
|
||||||
|
private static (CefMenuCommand Id, string Text) OpenInNewTab { get; } = (OpenInNewTabId, "Open in new tab");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the OpenInNewWindow.
|
||||||
|
/// </summary>
|
||||||
|
private static (CefMenuCommand Id, string Text) OpenInNewWindow { get; } = (OpenInNewWindowId, "Open in new window");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the SearchInWebsite.
|
||||||
|
/// </summary>
|
||||||
|
private static (CefMenuCommand Id, string Text) SearchInWebsite { get; } = (SearchInWebsiteId, "Search in Youtube");
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnBeforeContextMenu.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="frame">The frame<see cref="IFrame"/>.</param>
|
||||||
|
/// <param name="parameters">The parameters<see cref="IContextMenuParams"/>.</param>
|
||||||
|
/// <param name="model">The model<see cref="IMenuModel"/>.</param>
|
||||||
|
public virtual void OnBeforeContextMenu(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model)
|
||||||
|
{
|
||||||
|
var linkExist = !string.IsNullOrEmpty(parameters.LinkUrl);
|
||||||
|
var selectionTextExist = !string.IsNullOrEmpty(parameters.SelectionText);
|
||||||
|
var sourceUrlExist = !string.IsNullOrEmpty(parameters.SourceUrl);
|
||||||
|
|
||||||
|
if (linkExist || selectionTextExist)
|
||||||
|
{
|
||||||
|
model.AddSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
////model.Clear();
|
||||||
|
if (linkExist)
|
||||||
|
{
|
||||||
|
this.AddItem(model, CopyLinkAddress.Id, CopyLinkAddress.Text);
|
||||||
|
this.AddItem(model, OpenInNewTab.Id, OpenInNewTab.Text);
|
||||||
|
this.AddItem(model, OpenInNewWindow.Id, OpenInNewWindow.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceUrlExist && (parameters.SourceUrl != parameters.PageUrl))
|
||||||
|
{
|
||||||
|
if (parameters.SourceUrl.IsImageUrl())
|
||||||
|
{
|
||||||
|
this.AddItem(model, OpenImageInNewTab.Id, OpenImageInNewTab.Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectionTextExist)
|
||||||
|
{
|
||||||
|
this.AddItem(model, SearchInWebsite.Id, SearchInWebsite.Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnContextMenuCommand.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="frame">The frame<see cref="IFrame"/>.</param>
|
||||||
|
/// <param name="parameters">The parameters<see cref="IContextMenuParams"/>.</param>
|
||||||
|
/// <param name="commandId">The commandId<see cref="CefMenuCommand"/>.</param>
|
||||||
|
/// <param name="eventFlags">The eventFlags<see cref="CefEventFlags"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
public virtual bool OnContextMenuCommand(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnContextMenuDismissed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="frame">The frame<see cref="IFrame"/>.</param>
|
||||||
|
public virtual void OnContextMenuDismissed(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame)
|
||||||
|
{
|
||||||
|
var webBrowser = (ChromiumWebBrowser)chromiumWebBrowser;
|
||||||
|
webBrowser.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
webBrowser.ContextMenu = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetMenuItems.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The model<see cref="IMenuModel"/>.</param>
|
||||||
|
/// <returns>The <see cref="IEnumerable{Tuple{string, CefMenuCommand, bool}}"/>.</returns>
|
||||||
|
private static IEnumerable<Tuple<string, CefMenuCommand, bool>> GetMenuItems(IMenuModel model)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < model.Count; i++)
|
||||||
|
{
|
||||||
|
var header = model.GetLabelAt(i);
|
||||||
|
var commandId = model.GetCommandIdAt(i);
|
||||||
|
var isEnabled = model.IsEnabledAt(i);
|
||||||
|
yield return new Tuple<string, CefMenuCommand, bool>(header, commandId, isEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The AddItem.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The model<see cref="IMenuModel"/>.</param>
|
||||||
|
/// <param name="id">The id<see cref="CefMenuCommand"/>.</param>
|
||||||
|
/// <param name="label">The label<see cref="string"/>.</param>
|
||||||
|
private void AddItem(IMenuModel model, CefMenuCommand id, string label)
|
||||||
|
{
|
||||||
|
model.AddItem(id, label);
|
||||||
|
model.SetEnabled(id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The RunContextMenu.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="frame">The frame<see cref="IFrame"/>.</param>
|
||||||
|
/// <param name="parameters">The parameters<see cref="IContextMenuParams"/>.</param>
|
||||||
|
/// <param name="model">The model<see cref="IMenuModel"/>.</param>
|
||||||
|
/// <param name="callback">The callback<see cref="IRunContextMenuCallback"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
bool IContextMenuHandler.RunContextMenu(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback)
|
||||||
|
{
|
||||||
|
//NOTE: Return false to use the built in Context menu - in WPF this requires you integrate into your existing message loop, read the General Usage Guide for more details
|
||||||
|
//https://github.com/cefsharp/CefSharp/wiki/General-Usage#multithreadedmessageloop
|
||||||
|
//return false;
|
||||||
|
|
||||||
|
var webBrowser = (ChromiumWebBrowser)chromiumWebBrowser;
|
||||||
|
|
||||||
|
//IMenuModel is only valid in the context of this method, so need to read the values before invoking on the UI thread
|
||||||
|
var menuItems = GetMenuItems(model).ToList();
|
||||||
|
var linkUrl = parameters.LinkUrl;
|
||||||
|
var sourceUrl = parameters.SourceUrl;
|
||||||
|
var selectionText = parameters.SelectionText;
|
||||||
|
|
||||||
|
webBrowser.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
var menu = new ContextMenu
|
||||||
|
{
|
||||||
|
IsOpen = true
|
||||||
|
};
|
||||||
|
|
||||||
|
RoutedEventHandler handler = null;
|
||||||
|
|
||||||
|
handler = (s, e) =>
|
||||||
|
{
|
||||||
|
menu.Closed -= handler;
|
||||||
|
|
||||||
|
//If the callback has been disposed then it's already been executed
|
||||||
|
//so don't call Cancel
|
||||||
|
if (!callback.IsDisposed)
|
||||||
|
{
|
||||||
|
callback.Cancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
menu.Closed += handler;
|
||||||
|
|
||||||
|
foreach (var item in menuItems)
|
||||||
|
{
|
||||||
|
if (item.Item2 == CefMenuCommand.NotFound && string.IsNullOrWhiteSpace(item.Item1))
|
||||||
|
{
|
||||||
|
menu.Items.Add(new Separator());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.Items.Add(new MenuItem
|
||||||
|
{
|
||||||
|
Header = item.Item1.Replace("&", "_"),
|
||||||
|
IsEnabled = item.Item3,
|
||||||
|
Command = new RelayCommand((o) =>
|
||||||
|
{
|
||||||
|
//BUG: CEF currently not executing callbacks correctly so we manually map the commands below
|
||||||
|
//see https://github.com/cefsharp/CefSharp/issues/1767
|
||||||
|
//The following line worked in previous versions, it doesn't now, so custom EXAMPLE below
|
||||||
|
//callback.Continue(item.Item2, CefEventFlags.None);
|
||||||
|
|
||||||
|
//NOTE: Note all menu item options below have been tested, you can work out the rest
|
||||||
|
switch (item.Item2)
|
||||||
|
{
|
||||||
|
////case CefMenuCommand.Copy:
|
||||||
|
//// Clipboard.SetText(parameters.SelectionText);
|
||||||
|
//// break;
|
||||||
|
|
||||||
|
////case CefMenuCommand.Paste:
|
||||||
|
//// chromiumWebBrowser.Paste();
|
||||||
|
//// break;
|
||||||
|
|
||||||
|
case CopyLinkAdressId:
|
||||||
|
Clipboard.SetText(linkUrl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpenImageInNewTabId:
|
||||||
|
this.OpenInNewTabAction?.Invoke(sourceUrl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpenInNewWindowId:
|
||||||
|
this.OpenInNewWindowAction?.Invoke(linkUrl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpenInNewTabId:
|
||||||
|
this.OpenInNewTabAction?.Invoke(linkUrl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SearchInWebsiteId:
|
||||||
|
var searchUrl = $"{this.SearchEngineQuery}{selectionText}";
|
||||||
|
this.OpenInNewTabAction?.Invoke(searchUrl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CefMenuCommand.Back:
|
||||||
|
{
|
||||||
|
browser.GoBack();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.Forward:
|
||||||
|
{
|
||||||
|
browser.GoForward();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.Cut:
|
||||||
|
{
|
||||||
|
browser.FocusedFrame.Cut();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CefMenuCommand.Copy:
|
||||||
|
{
|
||||||
|
browser.FocusedFrame.Copy();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.Paste:
|
||||||
|
{
|
||||||
|
browser.FocusedFrame.Paste();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.Print:
|
||||||
|
{
|
||||||
|
browser.GetHost().Print();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.ViewSource:
|
||||||
|
{
|
||||||
|
browser.FocusedFrame.ViewSource();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.Undo:
|
||||||
|
{
|
||||||
|
browser.FocusedFrame.Undo();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.StopLoad:
|
||||||
|
{
|
||||||
|
browser.StopLoad();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.SelectAll:
|
||||||
|
{
|
||||||
|
browser.FocusedFrame.SelectAll();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.Redo:
|
||||||
|
{
|
||||||
|
browser.FocusedFrame.Redo();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.Find:
|
||||||
|
{
|
||||||
|
browser.GetHost().Find(parameters.SelectionText, true, false, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.AddToDictionary:
|
||||||
|
{
|
||||||
|
browser.GetHost().AddWordToDictionary(parameters.MisspelledWord);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.Reload:
|
||||||
|
{
|
||||||
|
browser.Reload();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CefMenuCommand.ReloadNoCache:
|
||||||
|
{
|
||||||
|
browser.Reload(ignoreCache: true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (CefMenuCommand)26501:
|
||||||
|
{
|
||||||
|
browser.GetHost().ShowDevTools();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (CefMenuCommand)26502:
|
||||||
|
{
|
||||||
|
browser.GetHost().CloseDevTools();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
webBrowser.ContextMenu = menu;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Handlers
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using CefSharp.Structs;
|
||||||
|
using CefSharp.Wpf;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using VideoBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="CefDisplayHandler" />.
|
||||||
|
/// </summary>
|
||||||
|
public class CefDisplayHandler : IDisplayHandler
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CefDisplayHandler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
internal CefDisplayHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the IsFullScreenCommand.
|
||||||
|
/// </summary>
|
||||||
|
internal ICommand IsFullScreenCommand { get; set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnAutoResize.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="newSize">The newSize<see cref="Size"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
public bool OnAutoResize(IWebBrowser chromiumWebBrowser, IBrowser browser, Size newSize)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnCursorChange.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="cursor">The cursor<see cref="IntPtr"/>.</param>
|
||||||
|
/// <param name="type">The type<see cref="CefSharp.Enums.CursorType"/>.</param>
|
||||||
|
/// <param name="customCursorInfo">The customCursorInfo<see cref="CursorInfo"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
public bool OnCursorChange(IWebBrowser chromiumWebBrowser, IBrowser browser, IntPtr cursor, CefSharp.Enums.CursorType type, CursorInfo customCursorInfo)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnLoadingProgressChange.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="progress">The progress<see cref="double"/>.</param>
|
||||||
|
public void OnLoadingProgressChange(IWebBrowser chromiumWebBrowser, IBrowser browser, double progress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnTooltipChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="text">The text<see cref="string"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
public bool OnTooltipChanged(IWebBrowser chromiumWebBrowser, ref string text)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnAddressChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="browserControl">The browserControl<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="addressChangedArgs">The addressChangedArgs<see cref="AddressChangedEventArgs"/>.</param>
|
||||||
|
void IDisplayHandler.OnAddressChanged(IWebBrowser browserControl, AddressChangedEventArgs addressChangedArgs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnConsoleMessage.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="browserControl">The browserControl<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="consoleMessageArgs">The consoleMessageArgs<see cref="ConsoleMessageEventArgs"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
bool IDisplayHandler.OnConsoleMessage(IWebBrowser browserControl, ConsoleMessageEventArgs consoleMessageArgs)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnFaviconUrlChange.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="browserControl">The browserControl<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="urls">The urls<see cref="IList{string}"/>.</param>
|
||||||
|
void IDisplayHandler.OnFaviconUrlChange(IWebBrowser browserControl, IBrowser browser, IList<string> urls)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnFullscreenModeChange.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="browserControl">The browserControl<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="fullscreen">The fullscreen<see cref="bool"/>.</param>
|
||||||
|
void IDisplayHandler.OnFullscreenModeChange(IWebBrowser browserControl, IBrowser browser, bool fullscreen)
|
||||||
|
{
|
||||||
|
var chromiumWebBrowser = (ChromiumWebBrowser)browserControl;
|
||||||
|
chromiumWebBrowser.Invoke(() =>
|
||||||
|
{
|
||||||
|
this.IsFullScreenCommand.Execute(fullscreen);
|
||||||
|
////if (fullscreen)
|
||||||
|
////{
|
||||||
|
//// parent = chromiumWebBrowser.Parent;
|
||||||
|
//// parent.Controls.Remove(chromiumWebBrowser);
|
||||||
|
|
||||||
|
//// fullScreenForm = new Form
|
||||||
|
//// {
|
||||||
|
//// FormBorderStyle = FormBorderStyle.None,
|
||||||
|
//// WindowState = FormWindowState.Maximized
|
||||||
|
//// };
|
||||||
|
//// fullScreenForm.Controls.Add(chromiumWebBrowser);
|
||||||
|
//// fullScreenForm.ShowDialog(parent.FindForm());
|
||||||
|
////}
|
||||||
|
////else
|
||||||
|
////{
|
||||||
|
//// fullScreenForm.Controls.Remove(chromiumWebBrowser);
|
||||||
|
//// parent.Controls.Add(chromiumWebBrowser);
|
||||||
|
//// fullScreenForm.Close();
|
||||||
|
//// fullScreenForm.Dispose();
|
||||||
|
//// fullScreenForm = null;
|
||||||
|
////}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnStatusMessage.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="browserControl">The browserControl<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="statusMessageArgs">The statusMessageArgs<see cref="StatusMessageEventArgs"/>.</param>
|
||||||
|
void IDisplayHandler.OnStatusMessage(IWebBrowser browserControl, StatusMessageEventArgs statusMessageArgs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnTitleChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="browserControl">The browserControl<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="titleChangedArgs">The titleChangedArgs<see cref="TitleChangedEventArgs"/>.</param>
|
||||||
|
void IDisplayHandler.OnTitleChanged(IWebBrowser browserControl, TitleChangedEventArgs titleChangedArgs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Handlers
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using CefSharp.Wpf;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using VideoBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="KeyboardHandler" />.
|
||||||
|
/// </summary>
|
||||||
|
public class CefKeyboardHandler : IKeyboardHandler
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CefKeyboardHandler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="host">The host<see cref="WebBrowser"/>.</param>
|
||||||
|
internal CefKeyboardHandler(FrameworkElement host)
|
||||||
|
{
|
||||||
|
this.WebBrowser = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the WebBrowser.
|
||||||
|
/// </summary>
|
||||||
|
public FrameworkElement WebBrowser { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsFullScreen.
|
||||||
|
/// </summary>
|
||||||
|
private bool IsFullScreen { get; set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnKeyEvent.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="type">The type<see cref="KeyType"/>.</param>
|
||||||
|
/// <param name="windowsKeyCode">The windowsKeyCode<see cref="int"/>.</param>
|
||||||
|
/// <param name="nativeKeyCode">The nativeKeyCode<see cref="int"/>.</param>
|
||||||
|
/// <param name="modifiers">The modifiers<see cref="CefEventFlags"/>.</param>
|
||||||
|
/// <param name="isSystemKey">The isSystemKey<see cref="bool"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
public bool OnKeyEvent(IWebBrowser chromiumWebBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return this.WebBrowser.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
var window = Window.GetWindow(this.WebBrowser);
|
||||||
|
var routedEvent = UIElement.KeyDownEvent;
|
||||||
|
var kb = Keyboard.PrimaryDevice;
|
||||||
|
var ps = PresentationSource.FromDependencyObject(this.WebBrowser);
|
||||||
|
var ts = 0;
|
||||||
|
var key = KeyInterop.KeyFromVirtualKey(windowsKeyCode);
|
||||||
|
|
||||||
|
var e = new System.Windows.Input.KeyEventArgs(kb, ps, ts, key)
|
||||||
|
{
|
||||||
|
RoutedEvent = routedEvent
|
||||||
|
};
|
||||||
|
|
||||||
|
// WPF gets modifiers from PrimaryKeyboard only
|
||||||
|
System.Diagnostics.Debug.WriteLine("Raising {0} {1}+{{{2}}}", routedEvent, key, Keyboard.Modifiers);
|
||||||
|
this.WebBrowser.RaiseEvent(e);
|
||||||
|
return e.Handled;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnPreKeyEvent.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="browserControl">The browserControl<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="type">The type<see cref="KeyType"/>.</param>
|
||||||
|
/// <param name="windowsKeyCode">The windowsKeyCode<see cref="int"/>.</param>
|
||||||
|
/// <param name="nativeKeyCode">The nativeKeyCode<see cref="int"/>.</param>
|
||||||
|
/// <param name="modifiers">The modifiers<see cref="CefEventFlags"/>.</param>
|
||||||
|
/// <param name="isSystemKey">The isSystemKey<see cref="bool"/>.</param>
|
||||||
|
/// <param name="isKeyboardShortcut">The isKeyboardShortcut<see cref="bool"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
|
||||||
|
{
|
||||||
|
var chromiumWebBrowser = (ChromiumWebBrowser)browserControl;
|
||||||
|
if ((Keys)windowsKeyCode == Keys.Escape)
|
||||||
|
{
|
||||||
|
chromiumWebBrowser.Invoke(delegate
|
||||||
|
{
|
||||||
|
////var screenSize = Screen.FromControl(chromiumWebBrowser).Bounds.Size;
|
||||||
|
////bool fullScreen = screenSize == chromiumWebBrowser.Size;
|
||||||
|
////if (fullScreen)
|
||||||
|
////{
|
||||||
|
//// chromiumWebBrowser.DisplayHandler.OnFullscreenModeChange(browserControl, browser, false);
|
||||||
|
////}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Handlers
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using CefSharp.Handler;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="CefRequestHandler" />.
|
||||||
|
/// </summary>
|
||||||
|
public class CefRequestHandler : RequestHandler
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the OpenUrlFromTabAction.
|
||||||
|
/// </summary>
|
||||||
|
internal Action<string> OpenUrlFromTabAction { get; set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnOpenUrlFromTab.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="frame">The frame<see cref="IFrame"/>.</param>
|
||||||
|
/// <param name="targetUrl">The targetUrl<see cref="string"/>.</param>
|
||||||
|
/// <param name="targetDisposition">The targetDisposition<see cref="WindowOpenDisposition"/>.</param>
|
||||||
|
/// <param name="userGesture">The userGesture<see cref="bool"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
protected override bool OnOpenUrlFromTab(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
|
||||||
|
{
|
||||||
|
this.OpenUrlFromTabAction?.Invoke(targetUrl);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Handlers
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using Ookii.Dialogs.Wpf;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Models;
|
||||||
|
using VideoBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="DownloadHandler" />.
|
||||||
|
/// </summary>
|
||||||
|
public class DownloadHandler : IDownloadHandler, IDisposable
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DownloadHandler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="downloadItemModels">The downloadItemModels<see cref="ICollection{DownloadItemModel}"/>.</param>
|
||||||
|
public DownloadHandler(IList<DownloadItemModel> downloadItemModels)
|
||||||
|
{
|
||||||
|
this.DownloadItemModels = downloadItemModels;
|
||||||
|
this.DownloadItemDict = new ConcurrentDictionary<int, DownloadProcessModel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether Disposed.
|
||||||
|
/// </summary>
|
||||||
|
public bool Disposed { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the DownloadItemDict.
|
||||||
|
/// </summary>
|
||||||
|
public IDictionary<int, DownloadProcessModel> DownloadItemDict { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the DownloadItemModels.
|
||||||
|
/// </summary>
|
||||||
|
public IList<DownloadItemModel> DownloadItemModels { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the DownloadPath.
|
||||||
|
/// </summary>
|
||||||
|
public string DownloadPath { get; set; } = AppEnvironment.UserVideoFolder;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsShowDialog.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsShowDialog { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsCancelAllDownloads.
|
||||||
|
/// </summary>
|
||||||
|
private bool IsCancelAllDownloads { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Lock.
|
||||||
|
/// </summary>
|
||||||
|
private object Lock { get; } = new object();
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Dispose.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (this.Disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnBeforeDownload.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="downloadItem">The downloadItem<see cref="DownloadItem"/>.</param>
|
||||||
|
/// <param name="callback">The callback<see cref="IBeforeDownloadCallback"/>.</param>
|
||||||
|
public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
|
||||||
|
{
|
||||||
|
lock (this.Lock)
|
||||||
|
{
|
||||||
|
if (this.DownloadItemDict.ContainsKey(downloadItem.Id) || callback.IsDisposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIThreadHelper.Invoke(() =>
|
||||||
|
{
|
||||||
|
using (callback)
|
||||||
|
{
|
||||||
|
var fileName = downloadItem.SuggestedFileName;
|
||||||
|
var filePath = Path.Combine(this.DownloadPath, downloadItem.SuggestedFileName);
|
||||||
|
if (this.IsShowDialog)
|
||||||
|
{
|
||||||
|
var dialog = new VistaSaveFileDialog
|
||||||
|
{
|
||||||
|
FileName = fileName,
|
||||||
|
CheckPathExists = true,
|
||||||
|
InitialDirectory = this.DownloadPath,
|
||||||
|
OverwritePrompt = true,
|
||||||
|
Title = "Save Link to...",
|
||||||
|
};
|
||||||
|
|
||||||
|
var element = chromiumWebBrowser as FrameworkElement;
|
||||||
|
|
||||||
|
var window = Window.GetWindow(element);
|
||||||
|
if (!(bool)dialog.ShowDialog(window))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath = dialog.FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.DownloadPath = Path.GetDirectoryName(filePath);
|
||||||
|
var model = new DownloadProcessModel(downloadItem);
|
||||||
|
this.DownloadItemDict.Add(downloadItem.Id, model);
|
||||||
|
this.DownloadItemModels.Insert(0, model);
|
||||||
|
callback.Continue(filePath, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnDownloadUpdated.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chromiumWebBrowser">The chromiumWebBrowser<see cref="IWebBrowser"/>.</param>
|
||||||
|
/// <param name="browser">The browser<see cref="IBrowser"/>.</param>
|
||||||
|
/// <param name="downloadItem">The downloadItem<see cref="DownloadItem"/>.</param>
|
||||||
|
/// <param name="callback">The callback<see cref="IDownloadItemCallback"/>.</param>
|
||||||
|
public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
|
||||||
|
{
|
||||||
|
lock (this.Lock)
|
||||||
|
{
|
||||||
|
var id = downloadItem.Id;
|
||||||
|
if (!this.DownloadItemDict.TryGetValue(id, out DownloadProcessModel processModel))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (processModel.IsCanceled || this.IsCancelAllDownloads)
|
||||||
|
{
|
||||||
|
this.DownloadItemDict.Remove(id);
|
||||||
|
this.DownloadItemModels.Remove(processModel);
|
||||||
|
callback.Cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
processModel.UpdateInfo(downloadItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Helpers
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internals are mostly from here: http://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using
|
||||||
|
/// Caches all results.
|
||||||
|
/// </summary>
|
||||||
|
public static class ApplicationIconHelper
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, ImageSource> _largeIconCache = new Dictionary<string, ImageSource>();
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, ImageSource> _smallIconCache = new Dictionary<string, ImageSource>();
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get an icon for a given filename.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileName">any filename.</param>
|
||||||
|
/// <param name="large">16x16 or 32x32 icon.</param>
|
||||||
|
/// <returns>null if path is null, otherwise - an icon.</returns>
|
||||||
|
public static ImageSource FindIconForFilename(this string fileName, bool large)
|
||||||
|
{
|
||||||
|
var extension = Path.GetExtension(fileName);
|
||||||
|
if (extension == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cache = large ? _largeIconCache : _smallIconCache;
|
||||||
|
ImageSource icon;
|
||||||
|
if (cache.TryGetValue(extension, out icon))
|
||||||
|
{
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
icon = IconReader.GetFileIcon(fileName, large ? IconReader.IconSize.Large : IconReader.IconSize.Small, false).ToImageSource();
|
||||||
|
cache.Add(extension, icon);
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// http://stackoverflow.com/a/6580799/1943849.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="icon">The icon<see cref="Icon"/>.</param>
|
||||||
|
/// <returns>The <see cref="ImageSource"/>.</returns>
|
||||||
|
private static ImageSource ToImageSource(this Icon icon)
|
||||||
|
{
|
||||||
|
var imageSource = Imaging.CreateBitmapSourceFromHIcon(
|
||||||
|
icon.Handle,
|
||||||
|
Int32Rect.Empty,
|
||||||
|
BitmapSizeOptions.FromEmptyOptions());
|
||||||
|
return imageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides static methods to read system icons for both folders and files.
|
||||||
|
/// </summary>
|
||||||
|
private static class IconReader
|
||||||
|
{
|
||||||
|
#region Enums
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Options to specify the size of icons to return.
|
||||||
|
/// </summary>
|
||||||
|
public enum IconSize
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specify large icon - 32 pixels by 32 pixels.
|
||||||
|
/// </summary>
|
||||||
|
Large = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specify small icon - 16 pixels by 16 pixels.
|
||||||
|
/// </summary>
|
||||||
|
Small = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Enums
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an icon for a given file - indicated by the name parameter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Pathname for file.</param>
|
||||||
|
/// <param name="size">Large or small.</param>
|
||||||
|
/// <param name="linkOverlay">Whether to include the link icon.</param>
|
||||||
|
/// <returns>System.Drawing.Icon.</returns>
|
||||||
|
public static Icon GetFileIcon(string name, IconSize size, bool linkOverlay)
|
||||||
|
{
|
||||||
|
var shfi = new Shell32.Shfileinfo();
|
||||||
|
var flags = Shell32.ShgfiIcon | Shell32.ShgfiUsefileattributes;
|
||||||
|
if (linkOverlay)
|
||||||
|
{
|
||||||
|
flags += Shell32.ShgfiLinkoverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the size specified for return. */
|
||||||
|
if (IconSize.Small == size)
|
||||||
|
{
|
||||||
|
flags += Shell32.ShgfiSmallicon;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flags += Shell32.ShgfiLargeicon;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shell32.SHGetFileInfo(name,
|
||||||
|
Shell32.FileAttributeNormal,
|
||||||
|
ref shfi,
|
||||||
|
(uint)Marshal.SizeOf(shfi),
|
||||||
|
flags);
|
||||||
|
// Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly
|
||||||
|
var icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone();
|
||||||
|
User32.DestroyIcon(shfi.hIcon); // Cleanup
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code
|
||||||
|
/// courtesy of MSDN Cold Rooster Consulting case study.
|
||||||
|
/// </summary>
|
||||||
|
private static class Shell32
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
public const uint FileAttributeNormal = 0x00000080;
|
||||||
|
|
||||||
|
public const uint ShgfiIcon = 0x000000100;// get icon
|
||||||
|
|
||||||
|
public const uint ShgfiLargeicon = 0x000000000;// get large icon
|
||||||
|
|
||||||
|
public const uint ShgfiLinkoverlay = 0x000008000;// put a link overlay on icon
|
||||||
|
|
||||||
|
public const uint ShgfiSmallicon = 0x000000001;// get small icon
|
||||||
|
|
||||||
|
public const uint ShgfiUsefileattributes = 0x000000010;// use passed dwFileAttribute
|
||||||
|
|
||||||
|
private const int MaxPath = 256;
|
||||||
|
|
||||||
|
#endregion Constants
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The SHGetFileInfo.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pszPath">The pszPath<see cref="string"/>.</param>
|
||||||
|
/// <param name="dwFileAttributes">The dwFileAttributes<see cref="uint"/>.</param>
|
||||||
|
/// <param name="psfi">The psfi<see cref="Shfileinfo"/>.</param>
|
||||||
|
/// <param name="cbFileInfo">The cbFileInfo<see cref="uint"/>.</param>
|
||||||
|
/// <param name="uFlags">The uFlags<see cref="uint"/>.</param>
|
||||||
|
/// <returns>The <see cref="IntPtr"/>.</returns>
|
||||||
|
[DllImport("Shell32.dll")]
|
||||||
|
public static extern IntPtr SHGetFileInfo(
|
||||||
|
string pszPath,
|
||||||
|
uint dwFileAttributes,
|
||||||
|
ref Shfileinfo psfi,
|
||||||
|
uint cbFileInfo,
|
||||||
|
uint uFlags
|
||||||
|
);
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="Shfileinfo" />.
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Shfileinfo
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
private const int Namesize = 80;
|
||||||
|
|
||||||
|
#endregion Constants
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
public readonly IntPtr hIcon;
|
||||||
|
|
||||||
|
private readonly uint dwAttributes;
|
||||||
|
|
||||||
|
private readonly int iIcon;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxPath)]
|
||||||
|
private readonly string szDisplayName;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Namesize)]
|
||||||
|
private readonly string szTypeName;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example.
|
||||||
|
/// </summary>
|
||||||
|
private static class User32
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to function required to delete handle. This method is used internally
|
||||||
|
/// and is not required to be called separately.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hIcon">Pointer to icon handle.</param>
|
||||||
|
/// <returns>N/A.</returns>
|
||||||
|
[DllImport("User32.dll")]
|
||||||
|
public static extern int DestroyIcon(IntPtr hIcon);
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
// Copyright © 2016 The CefSharp Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Helpers
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BrowserProcessHandler" />.
|
||||||
|
/// </summary>
|
||||||
|
public class BrowserProcessHandler : IBrowserProcessHandler
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The interval between calls to Cef.DoMessageLoopWork
|
||||||
|
/// </summary>
|
||||||
|
protected const int SixtyTimesPerSecond = 1000 / 60;// 60fps
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of milliseconds we're willing to wait between calls to OnScheduleMessagePumpWork().
|
||||||
|
/// </summary>
|
||||||
|
protected const int ThirtyTimesPerSecond = 1000 / 30;//30fps
|
||||||
|
|
||||||
|
#endregion Constants
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Dispose.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnScheduleMessagePumpWork.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="delay">The delay<see cref="int"/>.</param>
|
||||||
|
protected virtual void OnScheduleMessagePumpWork(int delay)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnContextInitialized.
|
||||||
|
/// </summary>
|
||||||
|
void IBrowserProcessHandler.OnContextInitialized()
|
||||||
|
{
|
||||||
|
//The Global CookieManager has been initialized, you can now set cookies
|
||||||
|
var cookieManager = Cef.GetGlobalCookieManager();
|
||||||
|
////cookieManager.SetSupportedSchemes(new string[] { "custom" }, true);
|
||||||
|
if (cookieManager.SetCookie("custom://cefsharp/home.html", new Cookie
|
||||||
|
{
|
||||||
|
Name = "CefSharpTestCookie",
|
||||||
|
Value = "ILikeCookies",
|
||||||
|
Expires = DateTime.Now.AddDays(1)
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
cookieManager.VisitUrlCookiesAsync("custom://cefsharp/home.html", false).ContinueWith(previous =>
|
||||||
|
{
|
||||||
|
if (previous.Status == TaskStatus.RanToCompletion)
|
||||||
|
{
|
||||||
|
var cookies = previous.Result;
|
||||||
|
|
||||||
|
foreach (var cookie in cookies)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("CookieName: " + cookie.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.WriteLine("No Cookies found");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cookieManager.VisitAllCookiesAsync().ContinueWith(t =>
|
||||||
|
{
|
||||||
|
if (t.Status == TaskStatus.RanToCompletion)
|
||||||
|
{
|
||||||
|
var cookies = t.Result;
|
||||||
|
|
||||||
|
foreach (var cookie in cookies)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("CookieName: " + cookie.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.WriteLine("No Cookies found");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//The Request Context has been initialized, you can now set preferences, like proxy server settings
|
||||||
|
//Dispose of context when finished - preferable not to keep a reference if possible.
|
||||||
|
using (var context = Cef.GetGlobalRequestContext())
|
||||||
|
{
|
||||||
|
string errorMessage;
|
||||||
|
//You can set most preferences using a `.` notation rather than having to create a complex set of dictionaries.
|
||||||
|
//The default is true, you can change to false to disable
|
||||||
|
context.SetPreference("webkit.webprefs.plugins_enabled", true, out errorMessage);
|
||||||
|
|
||||||
|
//string error;
|
||||||
|
//var dicts = new List<string> { "en-GB", "en-US" };
|
||||||
|
//var success = context.SetPreference("spellcheck.dictionaries", dicts, out error);
|
||||||
|
|
||||||
|
//The no-proxy-server flag is set in CefExample.cs class, you'll have to remove that before you can test
|
||||||
|
//this code out
|
||||||
|
//var v = new Dictionary<string, string>
|
||||||
|
//{
|
||||||
|
// ["mode"] = "fixed_servers",
|
||||||
|
// ["server"] = "scheme://host:port"
|
||||||
|
//};
|
||||||
|
//success = context.SetPreference("proxy", v, out errorMessage);
|
||||||
|
|
||||||
|
//It's possible to register a scheme handler for the default http and https schemes
|
||||||
|
//In this example we register the FolderSchemeHandlerFactory for https://cefsharp.example
|
||||||
|
//Best to include the domain name, so only requests for that domain are forwarded to your scheme handler
|
||||||
|
//It is possible to intercept all requests for a scheme, including the built in http/https ones, be very careful doing this!
|
||||||
|
////var folderSchemeHandlerExample = new FolderSchemeHandlerFactory(rootFolder: @"..\..\..\..\CefSharp.Example\Resources",
|
||||||
|
//// hostName: "cefsharp.example", //Optional param no hostname checking if null
|
||||||
|
//// defaultPage: "home.html"); //Optional param will default to index.html
|
||||||
|
|
||||||
|
////context.RegisterSchemeHandlerFactory("https", "cefsharp.example", folderSchemeHandlerExample);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnScheduleMessagePumpWork.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="delay">The delay<see cref="long"/>.</param>
|
||||||
|
void IBrowserProcessHandler.OnScheduleMessagePumpWork(long delay)
|
||||||
|
{
|
||||||
|
//If the delay is greater than the Maximum then use ThirtyTimesPerSecond
|
||||||
|
//instead - we do this to achieve a minimum number of FPS
|
||||||
|
if (delay > ThirtyTimesPerSecond)
|
||||||
|
{
|
||||||
|
delay = ThirtyTimesPerSecond;
|
||||||
|
}
|
||||||
|
OnScheduleMessagePumpWork((int)delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Helpers
|
||||||
|
{
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Windows;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Models;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.ViewModels;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BrowserSettingsHelper" />.
|
||||||
|
/// </summary>
|
||||||
|
internal static class BrowserSettingsHelper
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes static members of the <see cref="BrowserSettingsHelper"/> class.
|
||||||
|
/// </summary>
|
||||||
|
static BrowserSettingsHelper()
|
||||||
|
{
|
||||||
|
var appName = Assembly.GetExecutingAssembly().GetName().Name;
|
||||||
|
var userAppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||||
|
UserJsonSettingsPath = Path.Combine(userAppDataPath, $@"{appName}\BrowserSettings.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the UserJsonSettingsPath.
|
||||||
|
/// </summary>
|
||||||
|
public static string UserJsonSettingsPath { get; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Load.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="BrowserSettings"/>.</returns>
|
||||||
|
internal static BrowserSettings Load()
|
||||||
|
{
|
||||||
|
Logger.Info($"Loading Browser setting {UserJsonSettingsPath}");
|
||||||
|
if (!File.Exists(UserJsonSettingsPath))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (StreamReader file = File.OpenText(UserJsonSettingsPath))
|
||||||
|
{
|
||||||
|
JsonSerializer serializer = new JsonSerializer();
|
||||||
|
var browserSettings = (BrowserSettings)serializer.Deserialize(file, typeof(BrowserSettings));
|
||||||
|
return browserSettings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error($"Error Loading Browser Setting: {e.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Save.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="settings">The settings<see cref="BrowserSettings"/>.</param>
|
||||||
|
/// <param name="browserModel">The browserModel<see cref="WebBrowserTabControlViewModel"/>.</param>
|
||||||
|
internal static void Save(BrowserSettings settings, WebBrowserTabControlViewModel browserModel)
|
||||||
|
{
|
||||||
|
settings.BookmarkModels.Clear();
|
||||||
|
settings.DownloadItems.Clear();
|
||||||
|
settings.TabSettingModels.Clear();
|
||||||
|
foreach (var tabItem in browserModel.TabItems)
|
||||||
|
{
|
||||||
|
if (tabItem.Content is FrameworkElement element && element.DataContext is VideoBrowserViewModel videoModel)
|
||||||
|
{
|
||||||
|
var tabModel = new TabSettingsModel
|
||||||
|
{
|
||||||
|
Title = videoModel.Header,
|
||||||
|
Url = videoModel.Url
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.TabSettingModels.Add(tabModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var downloadItem in browserModel.GlobalBrowserData.DownloadItemModels)
|
||||||
|
{
|
||||||
|
if (downloadItem.Status == "Completed")
|
||||||
|
{
|
||||||
|
settings.DownloadItems.Add(new DownloadItemModel(downloadItem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.SelectedTabSettingIndex = browserModel.SelectedTabIndex;
|
||||||
|
var settingsFolder = Path.GetDirectoryName(UserJsonSettingsPath);
|
||||||
|
if (!Directory.Exists(settingsFolder))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(settingsFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
var serializer = new JsonSerializer();
|
||||||
|
serializer.Converters.Add(new JavaScriptDateTimeConverter());
|
||||||
|
serializer.NullValueHandling = NullValueHandling.Ignore;
|
||||||
|
|
||||||
|
using (var sw = new StreamWriter(UserJsonSettingsPath))
|
||||||
|
using (var writer = new JsonTextWriter(sw))
|
||||||
|
{
|
||||||
|
serializer.Serialize(writer, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Info($"Browser setting is saved in {UserJsonSettingsPath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
300
VideoBrowser/Controls/CefSharpBrowser/Helpers/CefConfig.cs
Normal file
300
VideoBrowser/Controls/CefSharpBrowser/Helpers/CefConfig.cs
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
// Copyright © 2014 The CefSharp Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Helpers
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
public static class CefConfig
|
||||||
|
{
|
||||||
|
//TODO: Revert after https://bitbucket.org/chromiumembedded/cef/issues/2685/networkservice-custom-scheme-unable-to
|
||||||
|
//has been fixed.
|
||||||
|
public const string ExampleDomain = "cefsharp.example";
|
||||||
|
|
||||||
|
public const string BaseUrl = "https://" + ExampleDomain;
|
||||||
|
public const string DefaultUrl = BaseUrl + "/home.html";
|
||||||
|
public const string BindingTestUrl = BaseUrl + "/BindingTest.html";
|
||||||
|
public const string BindingTestSingleUrl = BaseUrl + "/BindingTestSingle.html";
|
||||||
|
public const string BindingTestsAsyncTaskUrl = BaseUrl + "/BindingTestsAsyncTask.html";
|
||||||
|
public const string LegacyBindingTestUrl = BaseUrl + "/LegacyBindingTest.html";
|
||||||
|
public const string PostMessageTestUrl = BaseUrl + "/PostMessageTest.html";
|
||||||
|
public const string PluginsTestUrl = BaseUrl + "/plugins.html";
|
||||||
|
public const string PopupTestUrl = BaseUrl + "/PopupTest.html";
|
||||||
|
public const string TooltipTestUrl = BaseUrl + "/TooltipTest.html";
|
||||||
|
public const string BasicSchemeTestUrl = BaseUrl + "/SchemeTest.html";
|
||||||
|
public const string ResponseFilterTestUrl = BaseUrl + "/ResponseFilterTest.html";
|
||||||
|
public const string DraggableRegionTestUrl = BaseUrl + "/DraggableRegionTest.html";
|
||||||
|
public const string DragDropCursorsTestUrl = BaseUrl + "/DragDropCursorsTest.html";
|
||||||
|
public const string CssAnimationTestUrl = BaseUrl + "/CssAnimationTest.html";
|
||||||
|
public const string CdmSupportTestUrl = BaseUrl + "/CdmSupportTest.html";
|
||||||
|
public const string BindingApiCustomObjectNameTestUrl = BaseUrl + "/BindingApiCustomObjectNameTest.html";
|
||||||
|
public const string TestResourceUrl = "http://test/resource/load";
|
||||||
|
public const string RenderProcessCrashedUrl = "http://processcrashed";
|
||||||
|
public const string TestUnicodeResourceUrl = "http://test/resource/loadUnicode";
|
||||||
|
public const string PopupParentUrl = "http://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_win_close";
|
||||||
|
|
||||||
|
// Use when debugging the actual SubProcess, to make breakpoints etc. inside that project work.
|
||||||
|
private static readonly bool DebuggingSubProcess = Debugger.IsAttached;
|
||||||
|
|
||||||
|
private static string PluginInformation = "";
|
||||||
|
|
||||||
|
public static void Init(CefSettingsBase settings, IBrowserProcessHandler browserProcessHandler)
|
||||||
|
{
|
||||||
|
// Set Google API keys, used for Geolocation requests sans GPS. See http://www.chromium.org/developers/how-tos/api-keys
|
||||||
|
// Environment.SetEnvironmentVariable("GOOGLE_API_KEY", "");
|
||||||
|
// Environment.SetEnvironmentVariable("GOOGLE_DEFAULT_CLIENT_ID", "");
|
||||||
|
// Environment.SetEnvironmentVariable("GOOGLE_DEFAULT_CLIENT_SECRET", "");
|
||||||
|
|
||||||
|
// Widevine CDM registration - pass in directory where Widevine CDM binaries and manifest.json are located.
|
||||||
|
// For more information on support for DRM content with Widevine see: https://github.com/cefsharp/CefSharp/issues/1934
|
||||||
|
//Cef.RegisterWidevineCdm(@".\WidevineCdm");
|
||||||
|
|
||||||
|
//Chromium Command Line args
|
||||||
|
//http://peter.sh/experiments/chromium-command-line-switches/
|
||||||
|
//NOTE: Not all relevant in relation to `CefSharp`, use for reference purposes only.
|
||||||
|
//CEF specific command line args
|
||||||
|
//https://bitbucket.org/chromiumembedded/cef/src/master/libcef/common/cef_switches.cc?fileviewer=file-view-default
|
||||||
|
//IMPORTANT: For enabled/disabled command line arguments like disable-gpu specifying a value of "0" like
|
||||||
|
//settings.CefCommandLineArgs.Add("disable-gpu", "0"); will have no effect as the second argument is ignored.
|
||||||
|
|
||||||
|
settings.RemoteDebuggingPort = 8088;
|
||||||
|
//The location where cache data will be stored on disk. If empty an in-memory cache will be used for some features and a temporary disk cache for others.
|
||||||
|
//HTML5 databases such as localStorage will only persist across sessions if a cache path is specified.
|
||||||
|
settings.RootCachePath = Path.GetFullPath("cache");
|
||||||
|
//If non-null then CachePath must be equal to or a child of RootCachePath
|
||||||
|
//We're using a sub folder.
|
||||||
|
//
|
||||||
|
settings.CachePath = Path.GetFullPath("cache\\global");
|
||||||
|
//settings.UserAgent = "CefSharp Browser" + Cef.CefSharpVersion; // Example User Agent
|
||||||
|
//settings.CefCommandLineArgs.Add("renderer-process-limit", "1");
|
||||||
|
//settings.CefCommandLineArgs.Add("renderer-startup-dialog");
|
||||||
|
//settings.CefCommandLineArgs.Add("enable-media-stream"); //Enable WebRTC
|
||||||
|
//settings.CefCommandLineArgs.Add("no-proxy-server"); //Don't use a proxy server, always make direct connections. Overrides any other proxy server flags that are passed.
|
||||||
|
//settings.CefCommandLineArgs.Add("debug-plugin-loading"); //Dumps extra logging about plugin loading to the log file.
|
||||||
|
//settings.CefCommandLineArgs.Add("disable-plugins-discovery"); //Disable discovering third-party plugins. Effectively loading only ones shipped with the browser plus third-party ones as specified by --extra-plugin-dir and --load-plugin switches
|
||||||
|
//settings.CefCommandLineArgs.Add("enable-system-flash"); //Automatically discovered and load a system-wide installation of Pepper Flash.
|
||||||
|
//settings.CefCommandLineArgs.Add("allow-running-insecure-content"); //By default, an https page cannot run JavaScript, CSS or plugins from http URLs. This provides an override to get the old insecure behavior. Only available in 47 and above.
|
||||||
|
//https://peter.sh/experiments/chromium-command-line-switches/#disable-site-isolation-trials
|
||||||
|
//settings.CefCommandLineArgs.Add("disable-site-isolation-trials");
|
||||||
|
|
||||||
|
//settings.CefCommandLineArgs.Add("enable-logging"); //Enable Logging for the Renderer process (will open with a cmd prompt and output debug messages - use in conjunction with setting LogSeverity = LogSeverity.Verbose;)
|
||||||
|
//settings.LogSeverity = LogSeverity.Verbose; // Needed for enable-logging to output messages
|
||||||
|
|
||||||
|
//settings.CefCommandLineArgs.Add("disable-extensions"); //Extension support can be disabled
|
||||||
|
//settings.CefCommandLineArgs.Add("disable-pdf-extension"); //The PDF extension specifically can be disabled
|
||||||
|
|
||||||
|
//Load the pepper flash player that comes with Google Chrome - may be possible to load these values from the registry and query the dll for it's version info (Step 2 not strictly required it seems)
|
||||||
|
//settings.CefCommandLineArgs.Add("ppapi-flash-path", @"C:\Program Files (x86)\Google\Chrome\Application\47.0.2526.106\PepperFlash\pepflashplayer.dll"); //Load a specific pepper flash version (Step 1 of 2)
|
||||||
|
//settings.CefCommandLineArgs.Add("ppapi-flash-version", "20.0.0.228"); //Load a specific pepper flash version (Step 2 of 2)
|
||||||
|
|
||||||
|
//Audo play example
|
||||||
|
//settings.CefCommandLineArgs["autoplay-policy"] = "no-user-gesture-required";
|
||||||
|
|
||||||
|
//NOTE: For OSR best performance you should run with GPU disabled:
|
||||||
|
// `--disable-gpu --disable-gpu-compositing --enable-begin-frame-scheduling`
|
||||||
|
// (you'll loose WebGL support but gain increased FPS and reduced CPU usage).
|
||||||
|
// http://magpcss.org/ceforum/viewtopic.php?f=6&t=13271#p27075
|
||||||
|
//https://bitbucket.org/chromiumembedded/cef/commits/e3c1d8632eb43c1c2793d71639f3f5695696a5e8
|
||||||
|
|
||||||
|
//NOTE: The following function will set all three params
|
||||||
|
//settings.SetOffScreenRenderingBestPerformanceArgs();
|
||||||
|
//settings.CefCommandLineArgs.Add("disable-gpu");
|
||||||
|
//settings.CefCommandLineArgs.Add("disable-gpu-compositing");
|
||||||
|
//settings.CefCommandLineArgs.Add("enable-begin-frame-scheduling");
|
||||||
|
|
||||||
|
//settings.CefCommandLineArgs.Add("disable-gpu-vsync"); //Disable Vsync
|
||||||
|
|
||||||
|
// The following options control accessibility state for all frames.
|
||||||
|
// These options only take effect if accessibility state is not set by IBrowserHost.SetAccessibilityState call.
|
||||||
|
// --force-renderer-accessibility enables browser accessibility.
|
||||||
|
// --disable-renderer-accessibility completely disables browser accessibility.
|
||||||
|
//settings.CefCommandLineArgs.Add("force-renderer-accessibility");
|
||||||
|
//settings.CefCommandLineArgs.Add("disable-renderer-accessibility");
|
||||||
|
|
||||||
|
//Enables Uncaught exception handler
|
||||||
|
settings.UncaughtExceptionStackSize = 10;
|
||||||
|
|
||||||
|
//Disable WebAssembly
|
||||||
|
//settings.JavascriptFlags = "--noexpose_wasm";
|
||||||
|
|
||||||
|
// Off Screen rendering (WPF/Offscreen)
|
||||||
|
if (settings.WindowlessRenderingEnabled)
|
||||||
|
{
|
||||||
|
//Disable Direct Composition to test https://github.com/cefsharp/CefSharp/issues/1634
|
||||||
|
//settings.CefCommandLineArgs.Add("disable-direct-composition");
|
||||||
|
|
||||||
|
// DevTools doesn't seem to be working when this is enabled
|
||||||
|
// http://magpcss.org/ceforum/viewtopic.php?f=6&t=14095
|
||||||
|
//settings.CefCommandLineArgs.Add("enable-begin-frame-scheduling");
|
||||||
|
}
|
||||||
|
|
||||||
|
var proxy = ProxyConfig.GetProxyInformation();
|
||||||
|
switch (proxy.AccessType)
|
||||||
|
{
|
||||||
|
case InternetOpenType.Direct:
|
||||||
|
{
|
||||||
|
//Don't use a proxy server, always make direct connections.
|
||||||
|
settings.CefCommandLineArgs.Add("no-proxy-server");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case InternetOpenType.Proxy:
|
||||||
|
{
|
||||||
|
settings.CefCommandLineArgs.Add("proxy-server", proxy.ProxyAddress);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case InternetOpenType.PreConfig:
|
||||||
|
{
|
||||||
|
settings.CefCommandLineArgs.Add("proxy-auto-detect");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//settings.LogSeverity = LogSeverity.Verbose;
|
||||||
|
|
||||||
|
if (DebuggingSubProcess)
|
||||||
|
{
|
||||||
|
var architecture = Environment.Is64BitProcess ? "x64" : "x86";
|
||||||
|
var path = Path.GetFullPath("CefSharp.BrowserSubprocess.exe");
|
||||||
|
settings.BrowserSubprocessPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.RegisterScheme(new CefCustomScheme
|
||||||
|
{
|
||||||
|
SchemeName = CefSharpSchemeHandlerFactory.SchemeName,
|
||||||
|
SchemeHandlerFactory = new CefSharpSchemeHandlerFactory(),
|
||||||
|
IsSecure = true, //treated with the same security rules as those applied to "https" URLs
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.RegisterScheme(new CefCustomScheme
|
||||||
|
{
|
||||||
|
SchemeName = "https",
|
||||||
|
SchemeHandlerFactory = new CefSharpSchemeHandlerFactory(),
|
||||||
|
DomainName = ExampleDomain
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.RegisterScheme(new CefCustomScheme
|
||||||
|
{
|
||||||
|
SchemeName = CefSharpSchemeHandlerFactory.SchemeNameTest,
|
||||||
|
SchemeHandlerFactory = new CefSharpSchemeHandlerFactory(),
|
||||||
|
IsSecure = true //treated with the same security rules as those applied to "https" URLs
|
||||||
|
});
|
||||||
|
|
||||||
|
//You can use the http/https schemes - best to register for a specific domain
|
||||||
|
settings.RegisterScheme(new CefCustomScheme
|
||||||
|
{
|
||||||
|
SchemeName = "https",
|
||||||
|
SchemeHandlerFactory = new CefSharpSchemeHandlerFactory(),
|
||||||
|
DomainName = "cefsharp.com",
|
||||||
|
IsSecure = true //treated with the same security rules as those applied to "https" URLs
|
||||||
|
});
|
||||||
|
|
||||||
|
////settings.RegisterScheme(new CefCustomScheme
|
||||||
|
////{
|
||||||
|
//// SchemeName = "localfolder",
|
||||||
|
//// SchemeHandlerFactory = new FolderSchemeHandlerFactory(rootFolder: @"..\..\..\Resources",
|
||||||
|
//// schemeName: "localfolder", //Optional param no schemename checking if null
|
||||||
|
//// hostName: "cefsharp", //Optional param no hostname checking if null
|
||||||
|
//// defaultPage: "home.html") //Optional param will default to index.html
|
||||||
|
////});
|
||||||
|
|
||||||
|
////settings.RegisterExtension(new V8Extension("cefsharp/example", Resources.extension));
|
||||||
|
|
||||||
|
//This must be set before Cef.Initialized is called
|
||||||
|
CefSharpSettings.FocusedNodeChangedEnabled = true;
|
||||||
|
|
||||||
|
//Async Javascript Binding - methods are queued on TaskScheduler.Default.
|
||||||
|
//Set this to true to when you have methods that return Task<T>
|
||||||
|
//CefSharpSettings.ConcurrentTaskExecution = true;
|
||||||
|
|
||||||
|
//Legacy Binding Behaviour - Same as Javascript Binding in version 57 and below
|
||||||
|
//See issue https://github.com/cefsharp/CefSharp/issues/1203 for details
|
||||||
|
//CefSharpSettings.LegacyJavascriptBindingEnabled = true;
|
||||||
|
|
||||||
|
//Exit the subprocess if the parent process happens to close
|
||||||
|
//This is optional at the moment
|
||||||
|
//https://github.com/cefsharp/CefSharp/pull/2375/
|
||||||
|
CefSharpSettings.SubprocessExitIfParentProcessClosed = true;
|
||||||
|
|
||||||
|
//NOTE: Set this before any calls to Cef.Initialize to specify a proxy with username and password
|
||||||
|
//One set this cannot be changed at runtime. If you need to change the proxy at runtime (dynamically) then
|
||||||
|
//see https://github.com/cefsharp/CefSharp/wiki/General-Usage#proxy-resolution
|
||||||
|
//CefSharpSettings.Proxy = new ProxyOptions(ip: "127.0.0.1", port: "8080", username: "cefsharp", password: "123");
|
||||||
|
|
||||||
|
if (!Cef.Initialize(settings, performDependencyCheck: !DebuggingSubProcess, browserProcessHandler: browserProcessHandler))
|
||||||
|
{
|
||||||
|
throw new Exception("Unable to Initialize Cef");
|
||||||
|
}
|
||||||
|
|
||||||
|
Cef.AddCrossOriginWhitelistEntry(BaseUrl, "https", "cefsharp.com", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async void RegisterTestResources(IWebBrowser browser)
|
||||||
|
{
|
||||||
|
if (browser.ResourceRequestHandlerFactory == null)
|
||||||
|
{
|
||||||
|
browser.ResourceRequestHandlerFactory = new ResourceRequestHandlerFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
var handler = browser.ResourceRequestHandlerFactory as ResourceRequestHandlerFactory;
|
||||||
|
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
const string renderProcessCrashedBody = "<html><body><h1>Render Process Crashed</h1><p>Your seeing this message as the render process has crashed</p></body></html>";
|
||||||
|
handler.RegisterHandler(RenderProcessCrashedUrl, ResourceHandler.GetByteArray(renderProcessCrashedBody, Encoding.UTF8));
|
||||||
|
|
||||||
|
const string responseBody = "<html><body><h1>Success</h1><p>This document is loaded from a System.IO.Stream</p></body></html>";
|
||||||
|
handler.RegisterHandler(TestResourceUrl, ResourceHandler.GetByteArray(responseBody, Encoding.UTF8));
|
||||||
|
|
||||||
|
const string unicodeResponseBody = "<html><body>整体满意度</body></html>";
|
||||||
|
handler.RegisterHandler(TestUnicodeResourceUrl, ResourceHandler.GetByteArray(unicodeResponseBody, Encoding.UTF8));
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(PluginInformation))
|
||||||
|
{
|
||||||
|
var pluginBody = new StringBuilder();
|
||||||
|
pluginBody.Append("<html><body><h1>Plugins</h1><table>");
|
||||||
|
pluginBody.Append("<tr>");
|
||||||
|
pluginBody.Append("<th>Name</th>");
|
||||||
|
pluginBody.Append("<th>Description</th>");
|
||||||
|
pluginBody.Append("<th>Version</th>");
|
||||||
|
pluginBody.Append("<th>Path</th>");
|
||||||
|
pluginBody.Append("</tr>");
|
||||||
|
|
||||||
|
var plugins = await Cef.GetPlugins();
|
||||||
|
|
||||||
|
if (plugins.Count == 0)
|
||||||
|
{
|
||||||
|
pluginBody.Append("<tr>");
|
||||||
|
pluginBody.Append("<td colspan='4'>Cef.GetPlugins returned an empty list - likely no plugins were loaded on your system</td>");
|
||||||
|
pluginBody.Append("</tr>");
|
||||||
|
pluginBody.Append("<tr>");
|
||||||
|
pluginBody.Append("<td colspan='4'>You may find that NPAPI/PPAPI need to be enabled</td>");
|
||||||
|
pluginBody.Append("</tr>");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var plugin in plugins)
|
||||||
|
{
|
||||||
|
pluginBody.Append("<tr>");
|
||||||
|
pluginBody.Append("<td>" + plugin.Name + "</td>");
|
||||||
|
pluginBody.Append("<td>" + plugin.Description + "</td>");
|
||||||
|
pluginBody.Append("<td>" + plugin.Version + "</td>");
|
||||||
|
pluginBody.Append("<td>" + plugin.Path + "</td>");
|
||||||
|
pluginBody.Append("</tr>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginBody.Append("</table></body></html>");
|
||||||
|
|
||||||
|
PluginInformation = pluginBody.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.RegisterHandler(PluginsTestUrl, ResourceHandler.GetByteArray(PluginInformation, Encoding.UTF8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
// Copyright © 2012 The CefSharp Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Helpers
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
internal class CefSharpSchemeHandler : ResourceHandler
|
||||||
|
{
|
||||||
|
public override CefReturnValue ProcessRequestAsync(IRequest request, ICallback callback)
|
||||||
|
{
|
||||||
|
var uri = new Uri(request.Url);
|
||||||
|
var fileName = uri.AbsolutePath;
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
using (callback)
|
||||||
|
{
|
||||||
|
Stream stream = null;
|
||||||
|
|
||||||
|
if (string.Equals(fileName, "/PostDataTest.html", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var postDataElement = request.PostData.Elements.FirstOrDefault();
|
||||||
|
stream = ResourceHandler.GetMemoryStream("Post Data: " + (postDataElement == null ? "null" : postDataElement.GetBody()), Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(fileName, "/PostDataAjaxTest.html", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var postData = request.PostData;
|
||||||
|
if (postData == null)
|
||||||
|
{
|
||||||
|
stream = ResourceHandler.GetMemoryStream("Post Data: null", Encoding.UTF8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var postDataElement = postData.Elements.FirstOrDefault();
|
||||||
|
stream = ResourceHandler.GetMemoryStream("Post Data: " + (postDataElement == null ? "null" : postDataElement.GetBody()), Encoding.UTF8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream == null)
|
||||||
|
{
|
||||||
|
callback.Cancel();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Reset the stream position to 0 so the stream can be copied into the underlying unmanaged buffer
|
||||||
|
stream.Position = 0;
|
||||||
|
//Populate the response values - No longer need to implement GetResponseHeaders (unless you need to perform a redirect)
|
||||||
|
ResponseLength = stream.Length;
|
||||||
|
MimeType = "text/html";
|
||||||
|
StatusCode = (int)HttpStatusCode.OK;
|
||||||
|
Stream = stream;
|
||||||
|
|
||||||
|
callback.Continue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return CefReturnValue.ContinueAsync;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
// Copyright © 2013 The CefSharp Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Helpers
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
public class CefSharpSchemeHandlerFactory : ISchemeHandlerFactory
|
||||||
|
{
|
||||||
|
public const string SchemeName = "custom";
|
||||||
|
public const string SchemeNameTest = "test";
|
||||||
|
|
||||||
|
private static readonly IDictionary<string, string> ResourceDictionary;
|
||||||
|
|
||||||
|
static CefSharpSchemeHandlerFactory()
|
||||||
|
{
|
||||||
|
ResourceDictionary = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
////{ "/home.html", Resources.home_html },
|
||||||
|
|
||||||
|
////{ "/assets/css/shCore.css", Resources.assets_css_shCore_css },
|
||||||
|
////{ "/assets/css/shCoreDefault.css", Resources.assets_css_shCoreDefault_css },
|
||||||
|
////{ "/assets/css/docs.css", Resources.assets_css_docs_css },
|
||||||
|
////{ "/assets/js/application.js", Resources.assets_js_application_js },
|
||||||
|
////{ "/assets/js/jquery.js", Resources.assets_js_jquery_js },
|
||||||
|
////{ "/assets/js/shBrushCSharp.js", Resources.assets_js_shBrushCSharp_js },
|
||||||
|
////{ "/assets/js/shBrushJScript.js", Resources.assets_js_shBrushJScript_js },
|
||||||
|
////{ "/assets/js/shCore.js", Resources.assets_js_shCore_js },
|
||||||
|
|
||||||
|
////{ "/bootstrap/bootstrap-theme.min.css", Resources.bootstrap_theme_min_css },
|
||||||
|
////{ "/bootstrap/bootstrap.min.css", Resources.bootstrap_min_css },
|
||||||
|
////{ "/bootstrap/bootstrap.min.js", Resources.bootstrap_min_js },
|
||||||
|
|
||||||
|
////{ "/BindingTest.html", Resources.BindingTest },
|
||||||
|
////{ "/BindingTestSingle.html", Resources.BindingTestSingle },
|
||||||
|
////{ "/LegacyBindingTest.html", Resources.LegacyBindingTest },
|
||||||
|
////{ "/PostMessageTest.html", Resources.PostMessageTest },
|
||||||
|
////{ "/ExceptionTest.html", Resources.ExceptionTest },
|
||||||
|
////{ "/PopupTest.html", Resources.PopupTest },
|
||||||
|
////{ "/SchemeTest.html", Resources.SchemeTest },
|
||||||
|
////{ "/TooltipTest.html", Resources.TooltipTest },
|
||||||
|
////{ "/FramedWebGLTest.html", Resources.FramedWebGLTest },
|
||||||
|
////{ "/MultiBindingTest.html", Resources.MultiBindingTest },
|
||||||
|
////{ "/ScriptedMethodsTest.html", Resources.ScriptedMethodsTest },
|
||||||
|
////{ "/ResponseFilterTest.html", Resources.ResponseFilterTest },
|
||||||
|
////{ "/DraggableRegionTest.html", Resources.DraggableRegionTest },
|
||||||
|
////{ "/DragDropCursorsTest.html", Resources.DragDropCursorsTest },
|
||||||
|
////{ "/CssAnimationTest.html", Resources.CssAnimation },
|
||||||
|
////{ "/CdmSupportTest.html", Resources.CdmSupportTest },
|
||||||
|
////{ "/Recaptcha.html", Resources.Recaptcha },
|
||||||
|
////{ "/UnicodeExampleGreaterThan32kb.html", Resources.UnicodeExampleGreaterThan32kb },
|
||||||
|
////{ "/UnocodeExampleEqualTo32kb.html", Resources.UnocodeExampleEqualTo32kb },
|
||||||
|
////{ "/JavascriptCallbackTest.html", Resources.JavascriptCallbackTest },
|
||||||
|
////{ "/BindingTestsAsyncTask.html", Resources.BindingTestsAsyncTask },
|
||||||
|
////{ "/BindingApiCustomObjectNameTest.html", Resources.BindingApiCustomObjectNameTest }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
|
||||||
|
{
|
||||||
|
//Notes:
|
||||||
|
// - The 'host' portion is entirely ignored by this scheme handler.
|
||||||
|
// - If you register a ISchemeHandlerFactory for http/https schemes you should also specify a domain name
|
||||||
|
// - Avoid doing lots of processing in this method as it will affect performance.
|
||||||
|
// - Use the Default ResourceHandler implementation
|
||||||
|
|
||||||
|
var uri = new Uri(request.Url);
|
||||||
|
var fileName = uri.AbsolutePath;
|
||||||
|
|
||||||
|
//Load a file directly from Disk
|
||||||
|
if (fileName.EndsWith("CefSharp.Core.xml", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
//Convenient helper method to lookup the mimeType
|
||||||
|
var mimeType = Cef.GetMimeType("xml");
|
||||||
|
//Load a resource handler for CefSharp.Core.xml
|
||||||
|
//mimeType is optional and will default to text/html
|
||||||
|
return ResourceHandler.FromFilePath("CefSharp.Core.xml", mimeType, autoDisposeStream: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileName.EndsWith("Logo.png", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
//Convenient helper method to lookup the mimeType
|
||||||
|
var mimeType = Cef.GetMimeType("png");
|
||||||
|
//Load a resource handler for Logo.png
|
||||||
|
//mimeType is optional and will default to text/html
|
||||||
|
return ResourceHandler.FromFilePath("..\\..\\..\\..\\CefSharp.WinForms.Example\\Resources\\chromium-256.png", mimeType, autoDisposeStream: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uri.Host == "cefsharp.com" && schemeName == "https" && (string.Equals(fileName, "/PostDataTest.html", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(fileName, "/PostDataAjaxTest.html", StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
return new CefSharpSchemeHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(fileName, "/EmptyResponseFilterTest.html", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return ResourceHandler.FromString("", mimeType: ResourceHandler.DefaultMimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
string resource;
|
||||||
|
if (ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource))
|
||||||
|
{
|
||||||
|
var fileExtension = Path.GetExtension(fileName);
|
||||||
|
return ResourceHandler.FromString(resource, includePreamble: true, mimeType: Cef.GetMimeType(fileExtension));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright © 2014 The CefSharp Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Helpers
|
||||||
|
{
|
||||||
|
#region Enums
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the InternetOpenType.
|
||||||
|
/// </summary>
|
||||||
|
public enum InternetOpenType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the PreConfig.
|
||||||
|
/// </summary>
|
||||||
|
PreConfig = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the Direct.
|
||||||
|
/// </summary>
|
||||||
|
Direct = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the Proxy.
|
||||||
|
/// </summary>
|
||||||
|
Proxy = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the PreConfigWithNoAutoProxy.
|
||||||
|
/// </summary>
|
||||||
|
PreConfigWithNoAutoProxy = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Enums
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright © 2014 The CefSharp Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Helpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="InternetProxyInfo" />.
|
||||||
|
/// </summary>
|
||||||
|
public struct InternetProxyInfo
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
public InternetOpenType AccessType;
|
||||||
|
|
||||||
|
public string ProxyAddress;
|
||||||
|
|
||||||
|
public string ProxyBypass;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Helpers
|
||||||
|
{
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="ProcessHelper" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class ProcessHelper
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OpenFolder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">The filePath<see cref="string"/>.</param>
|
||||||
|
public static void OpenContainedFolder(string filePath)
|
||||||
|
{
|
||||||
|
var path = Path.GetDirectoryName(filePath);
|
||||||
|
Start(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OpenUrl.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">The url<see cref="string"/>.</param>
|
||||||
|
public static void OpenUrl(string url)
|
||||||
|
{
|
||||||
|
Start(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Start.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">The filePath<see cref="string"/>.</param>
|
||||||
|
public static void Start(string filePath)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var process = new Process
|
||||||
|
{
|
||||||
|
StartInfo = new ProcessStartInfo()
|
||||||
|
{
|
||||||
|
CreateNoWindow = true,
|
||||||
|
ErrorDialog = true,
|
||||||
|
FileName = filePath,
|
||||||
|
Verb = "Open"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
process.Start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
68
VideoBrowser/Controls/CefSharpBrowser/Helpers/ProxyConfig.cs
Normal file
68
VideoBrowser/Controls/CefSharpBrowser/Helpers/ProxyConfig.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright © 2015 The CefSharp Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Helpers
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="ProxyConfig" />.
|
||||||
|
/// </summary>
|
||||||
|
public class ProxyConfig
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
private const uint InternetOptionProxy = 38;
|
||||||
|
|
||||||
|
#endregion Constants
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetProxyInformation.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="InternetProxyInfo"/>.</returns>
|
||||||
|
public static InternetProxyInfo GetProxyInformation()
|
||||||
|
{
|
||||||
|
var bufferLength = 0;
|
||||||
|
InternetQueryOption(IntPtr.Zero, InternetOptionProxy, IntPtr.Zero, ref bufferLength);
|
||||||
|
var buffer = IntPtr.Zero;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
buffer = Marshal.AllocHGlobal(bufferLength);
|
||||||
|
|
||||||
|
if (InternetQueryOption(IntPtr.Zero, InternetOptionProxy, buffer, ref bufferLength))
|
||||||
|
{
|
||||||
|
var ipi = (InternetProxyInfo)Marshal.PtrToStructure(buffer, typeof(InternetProxyInfo));
|
||||||
|
return ipi;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Win32Exception();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (buffer != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The InternetQueryOption.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hInternet">The hInternet<see cref="IntPtr"/>.</param>
|
||||||
|
/// <param name="dwOption">The dwOption<see cref="uint"/>.</param>
|
||||||
|
/// <param name="lpBuffer">The lpBuffer<see cref="IntPtr"/>.</param>
|
||||||
|
/// <param name="lpdwBufferLength">The lpdwBufferLength<see cref="int"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
|
private static extern bool InternetQueryOption(IntPtr hInternet, uint dwOption, IntPtr lpBuffer, ref int lpdwBufferLength);
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
42
VideoBrowser/Controls/CefSharpBrowser/Helpers/UrlHelper.cs
Normal file
42
VideoBrowser/Controls/CefSharpBrowser/Helpers/UrlHelper.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Helpers
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="UrlHelper" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class UrlHelper
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The IsImageUrl.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="URL">The URL<see cref="string"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
public static bool IsImageUrl(this string URL)
|
||||||
|
{
|
||||||
|
if (!(HttpWebRequest.Create(URL) is HttpWebRequest req))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Method = "HEAD";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var resp = req.GetResponse())
|
||||||
|
{
|
||||||
|
return resp.ContentType.ToLower(CultureInfo.InvariantCulture).StartsWith("image/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
88
VideoBrowser/Controls/CefSharpBrowser/InterTabClient.cs
Normal file
88
VideoBrowser/Controls/CefSharpBrowser/InterTabClient.cs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser
|
||||||
|
{
|
||||||
|
using Dragablz;
|
||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Views;
|
||||||
|
using VideoBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="InterTabClient" />.
|
||||||
|
/// </summary>
|
||||||
|
public class InterTabClient : IInterTabClient
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InterTabClient"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The data<see cref="GlobalBrowserData"/>.</param>
|
||||||
|
internal InterTabClient(GlobalBrowserData data)
|
||||||
|
{
|
||||||
|
this.GlobalBrowserData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the CreateWindow.
|
||||||
|
/// </summary>
|
||||||
|
public Func<(Window, TabablzControl)> CreateWindow { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the GlobalBrowserData.
|
||||||
|
/// </summary>
|
||||||
|
public GlobalBrowserData GlobalBrowserData { get; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetNewHost.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="interTabClient">The interTabClient<see cref="IInterTabClient"/>.</param>
|
||||||
|
/// <param name="partition">The partition<see cref="object"/>.</param>
|
||||||
|
/// <param name="source">The source<see cref="TabablzControl"/>.</param>
|
||||||
|
/// <returns>The <see cref="INewTabHost{Window}"/>.</returns>
|
||||||
|
public INewTabHost<Window> GetNewHost(IInterTabClient interTabClient, object partition, TabablzControl source)
|
||||||
|
{
|
||||||
|
NewTabHost<Window> host = null;
|
||||||
|
UIThreadHelper.Invoke(() =>
|
||||||
|
{
|
||||||
|
var (window, tabControl) = this.CreateWindow != null ? this.CreateWindow() : this.CreateDefaultWindow();
|
||||||
|
host = new NewTabHost<Window>(window, tabControl);
|
||||||
|
});
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The TabEmptiedHandler.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tabControl">The tabControl<see cref="TabablzControl"/>.</param>
|
||||||
|
/// <param name="window">The window<see cref="Window"/>.</param>
|
||||||
|
/// <returns>The <see cref="TabEmptiedResponse"/>.</returns>
|
||||||
|
public TabEmptiedResponse TabEmptiedHandler(TabablzControl tabControl, Window window)
|
||||||
|
{
|
||||||
|
return TabEmptiedResponse.CloseWindowOrLayoutBranch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CreateDefaultWindow.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="(Window, TabablzControl)"/>.</returns>
|
||||||
|
internal (Window, TabablzControl) CreateDefaultWindow()
|
||||||
|
{
|
||||||
|
var viewModel = new DefaultTabHostViewModel(this.GlobalBrowserData);
|
||||||
|
var window = new DefaultTabHostWindow { DataContext = viewModel };
|
||||||
|
var tabControl = window.WebBrowserTabControlView.InitialTabablzControl;
|
||||||
|
return (window, tabControl);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Models
|
||||||
|
{
|
||||||
|
using System.ComponentModel;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BookmarkModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class BookmarkModel : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private string _name;
|
||||||
|
|
||||||
|
private string _url;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the PropertyChanged.
|
||||||
|
/// </summary>
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
#endregion Events
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get => _name; set => this.Set(this.PropertyChanged, ref _name, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Url.
|
||||||
|
/// </summary>
|
||||||
|
public string Url { get => _url; set => this.Set(this.PropertyChanged, ref _url, value); }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Models
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BrowserSettings" />.
|
||||||
|
/// </summary>
|
||||||
|
public class BrowserSettings
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BrowserSettings"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public BrowserSettings()
|
||||||
|
{
|
||||||
|
this.BookmarkModels = new List<BookmarkModel>();
|
||||||
|
this.DownloadItems = new List<DownloadItemModel>();
|
||||||
|
this.TabSettingModels = new List<TabSettingsModel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the BookmarkModels.
|
||||||
|
/// </summary>
|
||||||
|
public IList<BookmarkModel> BookmarkModels { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the DownloadItems.
|
||||||
|
/// </summary>
|
||||||
|
public IList<DownloadItemModel> DownloadItems { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the OutputFolder.
|
||||||
|
/// </summary>
|
||||||
|
public string OutputFolder { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the SelectedTabSettingIndex.
|
||||||
|
/// </summary>
|
||||||
|
public int SelectedTabSettingIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the TabSettingModels.
|
||||||
|
/// </summary>
|
||||||
|
public IList<TabSettingsModel> TabSettingModels { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Version.
|
||||||
|
/// </summary>
|
||||||
|
public string Version { get; set; } = "1.0";
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Models
|
||||||
|
{
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Helpers;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="DownloadItemModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class DownloadItemModel : NotifyPropertyChanged, IEquatable<DownloadItemModel>, IDisposable
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private string _fileSize;
|
||||||
|
|
||||||
|
private bool _isQueuedControlsVisible = true;
|
||||||
|
|
||||||
|
private string _outputPath;
|
||||||
|
|
||||||
|
private string _pauseText = "Pause";
|
||||||
|
|
||||||
|
private int _progress;
|
||||||
|
|
||||||
|
private string _status;
|
||||||
|
|
||||||
|
private string _thumbnail;
|
||||||
|
|
||||||
|
private string _title;
|
||||||
|
|
||||||
|
private string _url;
|
||||||
|
|
||||||
|
private bool Disposed = false;// To detect redundant calls
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DownloadItemModel"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public DownloadItemModel()
|
||||||
|
{
|
||||||
|
this.ExecuteDownloadedCommand = new RelayCommand(this.OnExecuteDownloaded, nameof(this.ExecuteDownloadedCommand));
|
||||||
|
this.ShowDownloadedFolderCommand = new RelayCommand(this.OnShowDownloadedFolderCommand, nameof(this.ShowDownloadedFolderCommand));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DownloadItemModel"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other<see cref="DownloadItemModel"/>.</param>
|
||||||
|
internal DownloadItemModel(DownloadItemModel other)
|
||||||
|
{
|
||||||
|
this.FileSize = other.FileSize;
|
||||||
|
this.IsApplicationThumbnail = other.IsApplicationThumbnail;
|
||||||
|
this.IsQueuedControlsVisible = other.IsQueuedControlsVisible;
|
||||||
|
this.OutputPath = other.OutputPath;
|
||||||
|
this.PauseText = other.PauseText;
|
||||||
|
this.Progress = other.Progress;
|
||||||
|
this.Status = other.Status;
|
||||||
|
this.Thumbnail = other.Thumbnail;
|
||||||
|
this.Title = other.Title;
|
||||||
|
this.Url = other.Url;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the CancelDownloadCommand.
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public ICommand CancelDownloadCommand { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the ExecuteDownloadedCommand.
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public ICommand ExecuteDownloadedCommand { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the FileSize.
|
||||||
|
/// </summary>
|
||||||
|
public string FileSize { get => this._fileSize; set => this.Set(this.PropertyChangedHandler, ref this._fileSize, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsApplicationThumbnail.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsApplicationThumbnail { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether IsCompletedControlsVisible.
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool IsCompletedControlsVisible { get => !this.IsQueuedControlsVisible; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsQueuedControlsVisible.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsQueuedControlsVisible
|
||||||
|
{
|
||||||
|
get => _isQueuedControlsVisible;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!this.Set(this.PropertyChangedHandler, ref _isQueuedControlsVisible, value))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.OnPropertyChanged(nameof(this.IsCompletedControlsVisible));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the OutputPath.
|
||||||
|
/// </summary>
|
||||||
|
public string OutputPath { get => _outputPath; set => this.Set(this.PropertyChangedHandler, ref _outputPath, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the PauseDownloadCommand.
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public ICommand PauseDownloadCommand { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the PauseText.
|
||||||
|
/// </summary>
|
||||||
|
public string PauseText { get => _pauseText; set => this.Set(this.PropertyChangedHandler, ref _pauseText, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Progress.
|
||||||
|
/// </summary>
|
||||||
|
public int Progress { get => this._progress; set => this.Set(this.PropertyChangedHandler, ref this._progress, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the ShowDownloadedFolderCommand.
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public ICommand ShowDownloadedFolderCommand { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Status.
|
||||||
|
/// </summary>
|
||||||
|
public string Status { get => this._status; set => this.Set(this.PropertyChangedHandler, ref this._status, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Thumbnail.
|
||||||
|
/// </summary>
|
||||||
|
public string Thumbnail { get => _thumbnail; set => this.Set(this.PropertyChangedHandler, ref _thumbnail, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Title.
|
||||||
|
/// </summary>
|
||||||
|
public string Title { get => this._title; set => this.Set(this.PropertyChangedHandler, ref this._title, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Url.
|
||||||
|
/// </summary>
|
||||||
|
public string Url { get => this._url; set => this.Set(this.PropertyChangedHandler, ref this._url, value); }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Dispose.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Equals.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other<see cref="DownloadItemModel"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
public bool Equals(DownloadItemModel other)
|
||||||
|
{
|
||||||
|
var isEqual = other != null && this.OutputPath == other.OutputPath;
|
||||||
|
return isEqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Equals.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return Equals(obj as DownloadItemModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetHashCode.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="int"/>.</returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
var hash = this.OutputPath == null ? string.Empty.GetHashCode() : this.OutputPath.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Dispose.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">The disposing<see cref="bool"/>.</param>
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!this.Disposed)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
// TODO: dispose managed state (managed objects).
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
|
||||||
|
// TODO: set large fields to null.
|
||||||
|
|
||||||
|
this.Disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnPlayMedia.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnExecuteDownloaded(object obj)
|
||||||
|
{
|
||||||
|
ProcessHelper.Start(this.OutputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnShowMediaInFolder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnShowDownloadedFolderCommand(object obj)
|
||||||
|
{
|
||||||
|
ProcessHelper.OpenContainedFolder(this.OutputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Models
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="DownloadProcessModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class DownloadProcessModel : DownloadItemModel
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DownloadProcessModel"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item<see cref="DownloadItem"/>.</param>
|
||||||
|
internal DownloadProcessModel(DownloadItem item)
|
||||||
|
{
|
||||||
|
this.Initialize(item);
|
||||||
|
this.IsApplicationThumbnail = true;
|
||||||
|
this.CancelDownloadCommand = new RelayCommand(this.OnCancelDownload, nameof(this.CancelDownloadCommand));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether IsCanceled.
|
||||||
|
/// </summary>
|
||||||
|
internal bool IsCanceled { get; private set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The UpdateInfo.
|
||||||
|
/// </summary>
|
||||||
|
internal void UpdateInfo(DownloadItem downloadItem)
|
||||||
|
{
|
||||||
|
this.OutputPath = downloadItem.FullPath;
|
||||||
|
this.Progress = downloadItem.PercentComplete;
|
||||||
|
var speed = $"{downloadItem.CurrentSpeed.FormatFileSize()}/s";
|
||||||
|
var percentComplete = $"{downloadItem.PercentComplete}%";
|
||||||
|
var completeStatus = "Completed";
|
||||||
|
this.Status = downloadItem.IsComplete ? completeStatus : $"{percentComplete} - {speed}";
|
||||||
|
if (this.Status == completeStatus)
|
||||||
|
{
|
||||||
|
this.IsQueuedControlsVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Thumbnail = this.OutputPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Initialize.
|
||||||
|
/// </summary>
|
||||||
|
private void Initialize(DownloadItem downloadItem)
|
||||||
|
{
|
||||||
|
this.FileSize = FormatString.FormatFileSize(downloadItem.TotalBytes);
|
||||||
|
this.Title = downloadItem.SuggestedFileName;
|
||||||
|
this.Url = downloadItem.OriginalUrl;
|
||||||
|
this.UpdateInfo(downloadItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnCancelDownload.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnCancelDownload(object obj)
|
||||||
|
{
|
||||||
|
this.IsCanceled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Models
|
||||||
|
{
|
||||||
|
using System.ComponentModel;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="TabSettingsModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class TabSettingsModel : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private string _title;
|
||||||
|
|
||||||
|
private string _url;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the PropertyChanged.
|
||||||
|
/// </summary>
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
#endregion Events
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Title.
|
||||||
|
/// </summary>
|
||||||
|
public string Title { get => _title; set => this.Set(this.PropertyChanged, ref _title, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Url.
|
||||||
|
/// </summary>
|
||||||
|
public string Url { get => _url; set => this.Set(this.PropertyChanged, ref _url, value); }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Resources
|
||||||
|
{
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BrowserIcons" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class BrowserIcons
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Lock.
|
||||||
|
/// </summary>
|
||||||
|
public static Geometry Lock { get; } = Geometry.Parse("M2,16L2,30 22,30 22,16z M12,2C8.14,2,5,5.141,5,9L5,14 19,14 19,9C19,5.14,15.86,2,12,2z M12,0C16.962,0,21,4.037,21,9L21,14 24,14 24,32 0,32 0,14 3,14 3,9C3,4,7,0,12,0z");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Star.
|
||||||
|
/// </summary>
|
||||||
|
public static Geometry Star { get; } = Geometry.Parse("M16,0L21,10.533997 32,12.223022 24,20.421997 25.889008,32 16,26.533997 6.1109924,32 8,20.421997 0,12.223022 11.057007,10.533997z");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the StarWF.
|
||||||
|
/// </summary>
|
||||||
|
public static Geometry StarWF { get; } = Geometry.Parse("M16,5.6780396L12.681,12.743042 5.2630005,13.877014 10.631989,19.378052 9.3639984,27.147034 16,23.48 22.634995,27.147034 21.366,19.378052 26.735,13.877014 19.317,12.743042z M16,0L20.942993,10.533997 32,12.223022 24,20.421997 25.886993,32 16,26.533997 6.111,32 8,20.421997 0,12.223 11,10.533997z");
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
}
|
||||||
|
}
|
||||||
1110
VideoBrowser/Controls/CefSharpBrowser/Resources/assets/css/docs.css
Normal file
1110
VideoBrowser/Controls/CefSharpBrowser/Resources/assets/css/docs.css
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,226 @@
|
|||||||
|
/**
|
||||||
|
* SyntaxHighlighter
|
||||||
|
* http://alexgorbatchev.com/SyntaxHighlighter
|
||||||
|
*
|
||||||
|
* SyntaxHighlighter is donationware. If you are using it, please donate.
|
||||||
|
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
|
||||||
|
*
|
||||||
|
* @version
|
||||||
|
* 3.0.83 (July 02 2010)
|
||||||
|
*
|
||||||
|
* @copyright
|
||||||
|
* Copyright (C) 2004-2010 Alex Gorbatchev.
|
||||||
|
*
|
||||||
|
* @license
|
||||||
|
* Dual licensed under the MIT and GPL licenses.
|
||||||
|
*/
|
||||||
|
.syntaxhighlighter a,
|
||||||
|
.syntaxhighlighter div,
|
||||||
|
.syntaxhighlighter code,
|
||||||
|
.syntaxhighlighter table,
|
||||||
|
.syntaxhighlighter table td,
|
||||||
|
.syntaxhighlighter table tr,
|
||||||
|
.syntaxhighlighter table tbody,
|
||||||
|
.syntaxhighlighter table thead,
|
||||||
|
.syntaxhighlighter table caption,
|
||||||
|
.syntaxhighlighter textarea {
|
||||||
|
-moz-border-radius: 0 0 0 0 !important;
|
||||||
|
-webkit-border-radius: 0 0 0 0 !important;
|
||||||
|
background: none !important;
|
||||||
|
border: 0 !important;
|
||||||
|
bottom: auto !important;
|
||||||
|
float: none !important;
|
||||||
|
height: auto !important;
|
||||||
|
left: auto !important;
|
||||||
|
line-height: 1.1em !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
outline: 0 !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
position: static !important;
|
||||||
|
right: auto !important;
|
||||||
|
text-align: left !important;
|
||||||
|
top: auto !important;
|
||||||
|
vertical-align: baseline !important;
|
||||||
|
width: auto !important;
|
||||||
|
box-sizing: content-box !important;
|
||||||
|
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important;
|
||||||
|
font-weight: normal !important;
|
||||||
|
font-style: normal !important;
|
||||||
|
font-size: 1em !important;
|
||||||
|
min-height: inherit !important;
|
||||||
|
min-height: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.syntaxhighlighter {
|
||||||
|
width: 100% !important;
|
||||||
|
margin: 1em 0 1em 0 !important;
|
||||||
|
position: relative !important;
|
||||||
|
overflow: auto !important;
|
||||||
|
font-size: 1em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.source {
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .bold {
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .italic {
|
||||||
|
font-style: italic !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .line {
|
||||||
|
white-space: pre !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table caption {
|
||||||
|
text-align: left !important;
|
||||||
|
padding: .5em 0 0.5em 1em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table td.code {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table td.code .container {
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table td.code .container textarea {
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
position: absolute !important;
|
||||||
|
left: 0 !important;
|
||||||
|
top: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
border: none !important;
|
||||||
|
background: white !important;
|
||||||
|
padding-left: 1em !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
white-space: pre !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table td.gutter .line {
|
||||||
|
text-align: right !important;
|
||||||
|
padding: 0 0.5em 0 1em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table td.code .line {
|
||||||
|
padding: 0 1em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line {
|
||||||
|
padding-left: 0em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.show {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed table {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed .toolbar {
|
||||||
|
padding: 0.1em 0.8em 0em 0.8em !important;
|
||||||
|
font-size: 1em !important;
|
||||||
|
position: static !important;
|
||||||
|
width: auto !important;
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed .toolbar span {
|
||||||
|
display: inline !important;
|
||||||
|
margin-right: 1em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed .toolbar span a {
|
||||||
|
padding: 0 !important;
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed .toolbar span a.expandSource {
|
||||||
|
display: inline !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .toolbar {
|
||||||
|
position: absolute !important;
|
||||||
|
right: 1px !important;
|
||||||
|
top: 1px !important;
|
||||||
|
width: 11px !important;
|
||||||
|
height: 11px !important;
|
||||||
|
font-size: 10px !important;
|
||||||
|
z-index: 10 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .toolbar span.title {
|
||||||
|
display: inline !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .toolbar a {
|
||||||
|
display: block !important;
|
||||||
|
text-align: center !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
padding-top: 1px !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .toolbar a.expandSource {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.ie {
|
||||||
|
font-size: .9em !important;
|
||||||
|
padding: 1px 0 1px 0 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.ie .toolbar {
|
||||||
|
line-height: 8px !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.ie .toolbar a {
|
||||||
|
padding-top: 0px !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .line.alt1 .content,
|
||||||
|
.syntaxhighlighter.printing .line.alt2 .content,
|
||||||
|
.syntaxhighlighter.printing .line.highlighted .number,
|
||||||
|
.syntaxhighlighter.printing .line.highlighted.alt1 .content,
|
||||||
|
.syntaxhighlighter.printing .line.highlighted.alt2 .content {
|
||||||
|
background: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .line .number {
|
||||||
|
color: #bbbbbb !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .line .content {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .toolbar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing a {
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a {
|
||||||
|
color: #008200 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a {
|
||||||
|
color: blue !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .keyword {
|
||||||
|
color: #006699 !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .preprocessor {
|
||||||
|
color: gray !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .variable {
|
||||||
|
color: #aa7700 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .value {
|
||||||
|
color: #009900 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .functions {
|
||||||
|
color: #ff1493 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .constants {
|
||||||
|
color: #0066cc !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .script {
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a {
|
||||||
|
color: gray !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a {
|
||||||
|
color: #ff1493 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a {
|
||||||
|
color: red !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
@@ -0,0 +1,328 @@
|
|||||||
|
/**
|
||||||
|
* SyntaxHighlighter
|
||||||
|
* http://alexgorbatchev.com/SyntaxHighlighter
|
||||||
|
*
|
||||||
|
* SyntaxHighlighter is donationware. If you are using it, please donate.
|
||||||
|
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
|
||||||
|
*
|
||||||
|
* @version
|
||||||
|
* 3.0.83 (July 02 2010)
|
||||||
|
*
|
||||||
|
* @copyright
|
||||||
|
* Copyright (C) 2004-2010 Alex Gorbatchev.
|
||||||
|
*
|
||||||
|
* @license
|
||||||
|
* Dual licensed under the MIT and GPL licenses.
|
||||||
|
*/
|
||||||
|
.syntaxhighlighter a,
|
||||||
|
.syntaxhighlighter div,
|
||||||
|
.syntaxhighlighter code,
|
||||||
|
.syntaxhighlighter table,
|
||||||
|
.syntaxhighlighter table td,
|
||||||
|
.syntaxhighlighter table tr,
|
||||||
|
.syntaxhighlighter table tbody,
|
||||||
|
.syntaxhighlighter table thead,
|
||||||
|
.syntaxhighlighter table caption,
|
||||||
|
.syntaxhighlighter textarea {
|
||||||
|
-moz-border-radius: 0 0 0 0 !important;
|
||||||
|
-webkit-border-radius: 0 0 0 0 !important;
|
||||||
|
background: none !important;
|
||||||
|
border: 0 !important;
|
||||||
|
bottom: auto !important;
|
||||||
|
float: none !important;
|
||||||
|
height: auto !important;
|
||||||
|
left: auto !important;
|
||||||
|
line-height: 1.1em !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
outline: 0 !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
position: static !important;
|
||||||
|
right: auto !important;
|
||||||
|
text-align: left !important;
|
||||||
|
top: auto !important;
|
||||||
|
vertical-align: baseline !important;
|
||||||
|
width: auto !important;
|
||||||
|
box-sizing: content-box !important;
|
||||||
|
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important;
|
||||||
|
font-weight: normal !important;
|
||||||
|
font-style: normal !important;
|
||||||
|
font-size: 1em !important;
|
||||||
|
min-height: inherit !important;
|
||||||
|
min-height: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.syntaxhighlighter {
|
||||||
|
width: 100% !important;
|
||||||
|
margin: 1em 0 1em 0 !important;
|
||||||
|
position: relative !important;
|
||||||
|
overflow: auto !important;
|
||||||
|
font-size: 1em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.source {
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .bold {
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .italic {
|
||||||
|
font-style: italic !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .line {
|
||||||
|
white-space: pre !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table caption {
|
||||||
|
text-align: left !important;
|
||||||
|
padding: .5em 0 0.5em 1em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table td.code {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table td.code .container {
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table td.code .container textarea {
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
position: absolute !important;
|
||||||
|
left: 0 !important;
|
||||||
|
top: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
border: none !important;
|
||||||
|
background: white !important;
|
||||||
|
padding-left: 1em !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
white-space: pre !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table td.gutter .line {
|
||||||
|
text-align: right !important;
|
||||||
|
padding: 0 0.5em 0 1em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table td.code .line {
|
||||||
|
padding: 0 1em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line {
|
||||||
|
padding-left: 0em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.show {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed table {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed .toolbar {
|
||||||
|
padding: 0.1em 0.8em 0em 0.8em !important;
|
||||||
|
font-size: 1em !important;
|
||||||
|
position: static !important;
|
||||||
|
width: auto !important;
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed .toolbar span {
|
||||||
|
display: inline !important;
|
||||||
|
margin-right: 1em !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed .toolbar span a {
|
||||||
|
padding: 0 !important;
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed .toolbar span a.expandSource {
|
||||||
|
display: inline !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .toolbar {
|
||||||
|
position: absolute !important;
|
||||||
|
right: 1px !important;
|
||||||
|
top: 1px !important;
|
||||||
|
width: 11px !important;
|
||||||
|
height: 11px !important;
|
||||||
|
font-size: 10px !important;
|
||||||
|
z-index: 10 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .toolbar span.title {
|
||||||
|
display: inline !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .toolbar a {
|
||||||
|
display: block !important;
|
||||||
|
text-align: center !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
padding-top: 1px !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .toolbar a.expandSource {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.ie {
|
||||||
|
font-size: .9em !important;
|
||||||
|
padding: 1px 0 1px 0 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.ie .toolbar {
|
||||||
|
line-height: 8px !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.ie .toolbar a {
|
||||||
|
padding-top: 0px !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .line.alt1 .content,
|
||||||
|
.syntaxhighlighter.printing .line.alt2 .content,
|
||||||
|
.syntaxhighlighter.printing .line.highlighted .number,
|
||||||
|
.syntaxhighlighter.printing .line.highlighted.alt1 .content,
|
||||||
|
.syntaxhighlighter.printing .line.highlighted.alt2 .content {
|
||||||
|
background: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .line .number {
|
||||||
|
color: #bbbbbb !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .line .content {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .toolbar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing a {
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a {
|
||||||
|
color: #008200 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a {
|
||||||
|
color: blue !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .keyword {
|
||||||
|
color: #006699 !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .preprocessor {
|
||||||
|
color: gray !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .variable {
|
||||||
|
color: #aa7700 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .value {
|
||||||
|
color: #009900 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .functions {
|
||||||
|
color: #ff1493 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .constants {
|
||||||
|
color: #0066cc !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .script {
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a {
|
||||||
|
color: gray !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a {
|
||||||
|
color: #ff1493 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a {
|
||||||
|
color: red !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.syntaxhighlighter {
|
||||||
|
background-color: white !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .line.alt1 {
|
||||||
|
background-color: white !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .line.alt2 {
|
||||||
|
background-color: white !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
|
||||||
|
background-color: #e0e0e0 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .line.highlighted.number {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter table caption {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .gutter {
|
||||||
|
color: #afafaf !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .gutter .line {
|
||||||
|
border-right: 3px solid #6ce26c !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .gutter .line.highlighted {
|
||||||
|
background-color: #6ce26c !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.printing .line .content {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed {
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed .toolbar {
|
||||||
|
color: blue !important;
|
||||||
|
background: white !important;
|
||||||
|
border: 1px solid #6ce26c !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed .toolbar a {
|
||||||
|
color: blue !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter.collapsed .toolbar a:hover {
|
||||||
|
color: red !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .toolbar {
|
||||||
|
color: white !important;
|
||||||
|
background: #6ce26c !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .toolbar a {
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .toolbar a:hover {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .plain, .syntaxhighlighter .plain a {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .comments, .syntaxhighlighter .comments a {
|
||||||
|
color: #008200 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .string, .syntaxhighlighter .string a {
|
||||||
|
color: blue !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .keyword {
|
||||||
|
color: #006699 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .preprocessor {
|
||||||
|
color: gray !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .variable {
|
||||||
|
color: #aa7700 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .value {
|
||||||
|
color: #009900 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .functions {
|
||||||
|
color: #ff1493 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .constants {
|
||||||
|
color: #0066cc !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .script {
|
||||||
|
font-weight: bold !important;
|
||||||
|
color: #006699 !important;
|
||||||
|
background-color: none !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .color1, .syntaxhighlighter .color1 a {
|
||||||
|
color: gray !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .color2, .syntaxhighlighter .color2 a {
|
||||||
|
color: #ff1493 !important;
|
||||||
|
}
|
||||||
|
.syntaxhighlighter .color3, .syntaxhighlighter .color3 a {
|
||||||
|
color: red !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.syntaxhighlighter .keyword {
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 320 KiB |
1
VideoBrowser/Controls/CefSharpBrowser/Resources/bootstrap/bootstrap-theme.min.css
vendored
Normal file
1
VideoBrowser/Controls/CefSharpBrowser/Resources/bootstrap/bootstrap-theme.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
9
VideoBrowser/Controls/CefSharpBrowser/Resources/bootstrap/bootstrap.min.css
vendored
Normal file
9
VideoBrowser/Controls/CefSharpBrowser/Resources/bootstrap/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
129
VideoBrowser/Controls/CefSharpBrowser/TabItem.cs
Normal file
129
VideoBrowser/Controls/CefSharpBrowser/TabItem.cs
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser
|
||||||
|
{
|
||||||
|
using Dragablz;
|
||||||
|
using System;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.ViewModels;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Views;
|
||||||
|
using VideoBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="TabItem" />.
|
||||||
|
/// </summary>
|
||||||
|
public class TabItem : HeaderedItemViewModel, IDisposable
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private Geometry _icon;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TabItem"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public TabItem() : this(Guid.Empty)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TabItem"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guid">The unique identifier.</param>
|
||||||
|
public TabItem(Guid guid)
|
||||||
|
{
|
||||||
|
this.Guid = guid;
|
||||||
|
this.HeaderViewModel = new WebBrowserTabHeaderViewModel { Header = "No Header" };
|
||||||
|
UIThreadHelper.Invoke(() =>
|
||||||
|
{
|
||||||
|
this.Header = new WebBrowserTabHeaderView { DataContext = this.HeaderViewModel };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether Disposed.
|
||||||
|
/// </summary>
|
||||||
|
public bool Disposed { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Guid.
|
||||||
|
/// </summary>
|
||||||
|
public Guid Guid { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the HeaderViewModel.
|
||||||
|
/// </summary>
|
||||||
|
public WebBrowserTabHeaderViewModel HeaderViewModel { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Icon.
|
||||||
|
/// </summary>
|
||||||
|
public Geometry Icon
|
||||||
|
{
|
||||||
|
get => _icon;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_icon == value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_icon = value;
|
||||||
|
this.OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Title.
|
||||||
|
/// </summary>
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get => this.HeaderViewModel.Header;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (this.Title == value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.HeaderViewModel.Header = value;
|
||||||
|
this.OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Dispose.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (this.Disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Disposed = true;
|
||||||
|
this.Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Dispose.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">The disposing<see cref="bool"/>.</param>
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
this.Content = null;
|
||||||
|
this.Header = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
71
VideoBrowser/Controls/CefSharpBrowser/UrlTextBox.xaml
Normal file
71
VideoBrowser/Controls/CefSharpBrowser/UrlTextBox.xaml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<Border
|
||||||
|
x:Class="VideoBrowser.Controls.CefSharpBrowser.UrlTextBox"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:converters="clr-namespace:VideoBrowser.Converters"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
x:Name="UrlTextBoxRoot"
|
||||||
|
Height="26"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
Background="WhiteSmoke"
|
||||||
|
BorderBrush="LightGray"
|
||||||
|
BorderThickness="1"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Border.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="../../Resources/IconsResource.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
<converters:BoolToVisibilityConverter
|
||||||
|
x:Key="BoolToVisibilityConverter"
|
||||||
|
FalseValue="Collapsed"
|
||||||
|
TrueValue="Visible" />
|
||||||
|
<Style x:Key="AddInItemsControl" TargetType="ItemsControl">
|
||||||
|
<Setter Property="ItemsPanel">
|
||||||
|
<Setter.Value>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="ItemTemplate">
|
||||||
|
<Setter.Value>
|
||||||
|
<DataTemplate>
|
||||||
|
<Path
|
||||||
|
Data="{Binding Icon}"
|
||||||
|
IsEnabled="{Binding IsEnabled}"
|
||||||
|
Stroke="DimGray"
|
||||||
|
Style="{StaticResource IconPathButtonBaseStyle}"
|
||||||
|
ToolTip="{Binding ToolTip}"
|
||||||
|
Visibility="{Binding IsVisible, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Height" Value="{Binding ElementName=UrlTextBoxGrid, Path=ActualHeight}" />
|
||||||
|
<Setter Property="Margin" Value="4,0,4,0" />
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Border.Resources>
|
||||||
|
<Grid x:Name="UrlTextBoxGrid">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Grid.Column="0">
|
||||||
|
<ItemsControl ItemsSource="{Binding ElementName=UrlTextBoxRoot, Path=LeftAddInButtons}" Style="{StaticResource AddInItemsControl}" />
|
||||||
|
</StackPanel>
|
||||||
|
<TextBox
|
||||||
|
x:Name="TextBox"
|
||||||
|
Grid.Column="1"
|
||||||
|
Height="{Binding ElementName=UrlTextBoxGrid, Path=ActualHeight}"
|
||||||
|
Margin="0"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderThickness="0"
|
||||||
|
Text="{Binding ElementName=UrlTextBoxRoot, Path=Url, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
<StackPanel Grid.Column="2">
|
||||||
|
<ItemsControl ItemsSource="{Binding ElementName=UrlTextBoxRoot, Path=RightAddInButtons}" Style="{StaticResource AddInItemsControl}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
159
VideoBrowser/Controls/CefSharpBrowser/UrlTextBox.xaml.cs
Normal file
159
VideoBrowser/Controls/CefSharpBrowser/UrlTextBox.xaml.cs
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser
|
||||||
|
{
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.AddIns;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for UrlTextBox.xaml.
|
||||||
|
/// </summary>
|
||||||
|
public partial class UrlTextBox
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
public static readonly DependencyProperty AddInButtonClickedProperty =
|
||||||
|
DependencyProperty.Register(nameof(AddInButtonClicked), typeof(ICommand), typeof(UrlTextBox), new PropertyMetadata(null));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty LeftAddInButtonsProperty =
|
||||||
|
DependencyProperty.Register(nameof(LeftAddInButtons), typeof(ObservableCollection<AddInButton>), typeof(UrlTextBox), new PropertyMetadata());
|
||||||
|
|
||||||
|
public static readonly DependencyProperty NavigateUrlCommandProperty =
|
||||||
|
DependencyProperty.Register(nameof(NavigateUrlCommand), typeof(ICommand), typeof(UrlTextBox), new PropertyMetadata(null));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty NavigateUrlProperty =
|
||||||
|
DependencyProperty.Register(nameof(NavigateUrl), typeof(string), typeof(UrlTextBox), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnNavigateUrlChanged));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty RightAddInButtonsProperty =
|
||||||
|
DependencyProperty.Register(nameof(RightAddInButtons), typeof(ObservableCollection<AddInButton>), typeof(UrlTextBox), new PropertyMetadata());
|
||||||
|
|
||||||
|
public static readonly DependencyProperty UrlProperty =
|
||||||
|
DependencyProperty.Register(nameof(Url), typeof(string), typeof(UrlTextBox), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnUrlChanged));
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UrlTextBox"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public UrlTextBox()
|
||||||
|
{
|
||||||
|
this.BookmarkAddIn = new BookmarkAddIn();
|
||||||
|
this.IsSecureAddIn = new IsSecureAddIn();
|
||||||
|
this.InternalNavigateUrlCommand = new RelayCommand(this.OnNavigateUrl, nameof(this.InternalNavigateUrlCommand));
|
||||||
|
this.InitializeComponent();
|
||||||
|
this.LeftAddInButtons = new ObservableCollection<AddInButton> { this.IsSecureAddIn };
|
||||||
|
this.RightAddInButtons = new ObservableCollection<AddInButton> { this.BookmarkAddIn };
|
||||||
|
this.TextBox.InputBindings.Add(new KeyBinding(this.InternalNavigateUrlCommand, Key.Enter, ModifierKeys.None));
|
||||||
|
this.GotFocus += this.OnUrlTextBox_GotFocus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the AddInButtonClicked.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand AddInButtonClicked
|
||||||
|
{
|
||||||
|
get { return (ICommand)GetValue(AddInButtonClickedProperty); }
|
||||||
|
set { SetValue(AddInButtonClickedProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the BookmarkAddIn.
|
||||||
|
/// </summary>
|
||||||
|
public BookmarkAddIn BookmarkAddIn { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the IsSecureAddIn.
|
||||||
|
/// </summary>
|
||||||
|
public IsSecureAddIn IsSecureAddIn { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the LeftAddInButtons.
|
||||||
|
/// </summary>
|
||||||
|
public ObservableCollection<AddInButton> LeftAddInButtons { get => (ObservableCollection<AddInButton>)GetValue(LeftAddInButtonsProperty); set => SetValue(LeftAddInButtonsProperty, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the NavigateUrl.
|
||||||
|
/// </summary>
|
||||||
|
public string NavigateUrl { get => (string)GetValue(NavigateUrlProperty); set => SetValue(NavigateUrlProperty, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the NavigateUrlCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand NavigateUrlCommand { get => (ICommand)GetValue(NavigateUrlCommandProperty); set => SetValue(NavigateUrlCommandProperty, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the RightAddInButtons.
|
||||||
|
/// </summary>
|
||||||
|
public ObservableCollection<AddInButton> RightAddInButtons { get => (ObservableCollection<AddInButton>)GetValue(RightAddInButtonsProperty); set => SetValue(RightAddInButtonsProperty, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Url.
|
||||||
|
/// </summary>
|
||||||
|
public string Url { get => (string)GetValue(UrlProperty); set => SetValue(UrlProperty, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the InternalNavigateUrlCommand.
|
||||||
|
/// </summary>
|
||||||
|
private ICommand InternalNavigateUrlCommand { get; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnNavigateUrlChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="d">The d<see cref="DependencyObject"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
|
||||||
|
private static void OnNavigateUrlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var textBox = (UrlTextBox)d;
|
||||||
|
var navigateUrl = e.NewValue.ToString();
|
||||||
|
textBox.BookmarkAddIn.Url = navigateUrl;
|
||||||
|
textBox.IsSecureAddIn.Url = navigateUrl;
|
||||||
|
textBox.Url = navigateUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnUrlChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="d">The d<see cref="DependencyObject"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
|
||||||
|
private static void OnUrlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var textBox = (UrlTextBox)d;
|
||||||
|
textBox.BookmarkAddIn.Url = string.Empty;
|
||||||
|
textBox.IsSecureAddIn.Url = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnNavigateUrl.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnNavigateUrl(object obj)
|
||||||
|
{
|
||||||
|
this.BookmarkAddIn.Url = this.Url;
|
||||||
|
this.IsSecureAddIn.Url = this.Url;
|
||||||
|
this.NavigateUrlCommand?.Execute(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnUrlTextBox_GotFocus.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender<see cref="object"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="RoutedEventArgs"/>.</param>
|
||||||
|
private void OnUrlTextBox_GotFocus(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.TextBox.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.ViewModels
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="DefaultTabHostViewModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class DefaultTabHostViewModel
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DefaultTabHostViewModel"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="globalData">The globalData<see cref="GlobalBrowserData"/>.</param>
|
||||||
|
public DefaultTabHostViewModel(GlobalBrowserData globalData)
|
||||||
|
{
|
||||||
|
this.WebBrowserTabControlViewModel = new WebBrowserTabControlViewModel(globalData);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the WebBrowserTabControlViewModel.
|
||||||
|
/// </summary>
|
||||||
|
public WebBrowserTabControlViewModel WebBrowserTabControlViewModel { get; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.ViewModels
|
||||||
|
{
|
||||||
|
using Ookii.Dialogs.Wpf;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Helpers;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Models;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
using VideoBrowser.Resources;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="SettingsViewModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class SettingsViewModel : NotifyPropertyChanged
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private string _outputFolder;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SettingsViewModel"/> class.
|
||||||
|
/// </summary>
|
||||||
|
internal SettingsViewModel()
|
||||||
|
{
|
||||||
|
this.GetFolderCommand = new RelayCommand(this.OnGetFolder);
|
||||||
|
var settings = BrowserSettingsHelper.Load();
|
||||||
|
if (settings != null)
|
||||||
|
{
|
||||||
|
this.BrowserSettings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputFolder = this.BrowserSettings.OutputFolder;
|
||||||
|
this.OutputFolder = string.IsNullOrEmpty(outputFolder) || !Directory.Exists(outputFolder) ? AppEnvironment.UserVideoFolder : outputFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the BrowserSettings.
|
||||||
|
/// </summary>
|
||||||
|
public BrowserSettings BrowserSettings { get; } = new BrowserSettings();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the GetFolderCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand GetFolderCommand { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Icon.
|
||||||
|
/// </summary>
|
||||||
|
public Geometry Icon { get; set; } = Icons.Settings;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the OutputFolder.
|
||||||
|
/// </summary>
|
||||||
|
public string OutputFolder
|
||||||
|
{
|
||||||
|
get => this._outputFolder;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.Set(this.PropertyChangedHandler, ref this._outputFolder, value);
|
||||||
|
if (Directory.Exists(this.OutputFolder))
|
||||||
|
{
|
||||||
|
this.BrowserSettings.OutputFolder = this.OutputFolder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the OutputType.
|
||||||
|
/// </summary>
|
||||||
|
public string OutputType { get; set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnGetFolder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnGetFolder(object obj)
|
||||||
|
{
|
||||||
|
var dialog = new VistaFolderBrowserDialog
|
||||||
|
{
|
||||||
|
Description = "Download Folder Location",
|
||||||
|
UseDescriptionForTitle = true,
|
||||||
|
SelectedPath = this.OutputFolder
|
||||||
|
};
|
||||||
|
|
||||||
|
var element = obj as FrameworkElement;
|
||||||
|
var window = Window.GetWindow(element);
|
||||||
|
if ((bool)dialog.ShowDialog(window))
|
||||||
|
{
|
||||||
|
this.OutputFolder = dialog.SelectedPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,346 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.ViewModels
|
||||||
|
{
|
||||||
|
using CefSharp;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Helpers;
|
||||||
|
using VideoBrowser.Core;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
using VideoBrowser.ViewModels;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="VideoBrowserViewModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class VideoBrowserViewModel : NotifyPropertyChanged, IDisposable
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private ICommand _backwardCommand;
|
||||||
|
|
||||||
|
private bool _canBackward;
|
||||||
|
|
||||||
|
private bool _canForward;
|
||||||
|
|
||||||
|
private CefWindowData _cefWindowData;
|
||||||
|
|
||||||
|
private ICommand _forwardCommand;
|
||||||
|
|
||||||
|
private string _header = "New Tab";
|
||||||
|
|
||||||
|
private string _navigateUrl = "youtube.com";
|
||||||
|
|
||||||
|
private ICommand _reloadCommand;
|
||||||
|
|
||||||
|
private IWebBrowser _webBrowser;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="VideoBrowserViewModel"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="globalBrowserData">The globalBrowserData<see cref="GlobalBrowserData"/>.</param>
|
||||||
|
/// <param name="windowData">The windowData<see cref="CefWindowData"/>.</param>
|
||||||
|
internal VideoBrowserViewModel(GlobalBrowserData globalBrowserData, CefWindowData windowData)
|
||||||
|
{
|
||||||
|
this.GlobalBrowserData = globalBrowserData;
|
||||||
|
this.CefWindowData = windowData;
|
||||||
|
|
||||||
|
// BackwardCommand and ForwardCommand are set by the View.
|
||||||
|
this.DownloadCommand = new RelayCommand(this.OnDownload, "Download", (o) => this.UrlReader.IsDownloadable);
|
||||||
|
this.HomeCommand = new RelayCommand(this.OnHome, "Home");
|
||||||
|
this.NavigateUrlCommand = new RelayCommand(this.OnNavigateUrl, "NavigateUrl");
|
||||||
|
this.OpenOutputFolderCommand = new RelayCommand(this.OnOpenOutputFolder, "Open output folder");
|
||||||
|
this.IndicatorColor = new SolidColorBrush(Colors.DarkBlue);
|
||||||
|
this.UrlEditor = new UrlEditorViewModel(this.UrlReader, this.GlobalBrowserData.Settings)
|
||||||
|
{
|
||||||
|
NavigateUrlCommand = this.NavigateUrlCommand,
|
||||||
|
ShowMessageAsyncAction = this.ShowMessageAsync
|
||||||
|
};
|
||||||
|
this.UrlEditor.PropertyChanged += this.OnUrlEditor_PropertyChanged;
|
||||||
|
this.PropertyChanged += this.OnPropertyChanged;
|
||||||
|
this.OnHome(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the AddInButtons.
|
||||||
|
/// </summary>
|
||||||
|
public ICollection<AddInButton> AddInButtons => this.GlobalBrowserData.AddInButtons;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the BackwardCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand BackwardCommand { get => this._backwardCommand; set => this.Set(this.PropertyChangedHandler, ref this._backwardCommand, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether CanBackward.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanBackward { get => this._canBackward; set => this.Set(this.PropertyChangedHandler, ref this._canBackward, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether CanForward.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanForward { get => this._canForward; set => this.Set(this.PropertyChangedHandler, ref this._canForward, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the CefWindowData.
|
||||||
|
/// </summary>
|
||||||
|
public CefWindowData CefWindowData
|
||||||
|
{
|
||||||
|
get => _cefWindowData;
|
||||||
|
internal set
|
||||||
|
{
|
||||||
|
if (!this.Set(this.PropertyChangedHandler, ref _cefWindowData, value))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.InitializeHandlers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the DownloadCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand DownloadCommand { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the ForwardCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand ForwardCommand { get => this._forwardCommand; set => this.Set(this.PropertyChangedHandler, ref this._forwardCommand, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the GlobalBrowserData.
|
||||||
|
/// </summary>
|
||||||
|
public GlobalBrowserData GlobalBrowserData { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Header.
|
||||||
|
/// </summary>
|
||||||
|
public string Header { get => _header; set => this.Set(this.PropertyChangedHandler, ref _header, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the HomeCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand HomeCommand { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the IndicatorColor.
|
||||||
|
/// </summary>
|
||||||
|
public Brush IndicatorColor { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the IsSuccessful.
|
||||||
|
/// </summary>
|
||||||
|
public bool? IsSuccessful
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
IndicatorColor = new SolidColorBrush(Colors.LightBlue);
|
||||||
|
else if (value == false)
|
||||||
|
IndicatorColor = new SolidColorBrush(Colors.Red);
|
||||||
|
else
|
||||||
|
IndicatorColor = new SolidColorBrush(Colors.Green);
|
||||||
|
OnPropertyChanged(nameof(IndicatorColor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the NavigateUrl.
|
||||||
|
/// The current valid Url that is currently opened,
|
||||||
|
/// it is set by Url property if the Return key is pressed or link is clicked...
|
||||||
|
/// </summary>
|
||||||
|
public string NavigateUrl { get => this._navigateUrl; set => this.Set(this.PropertyChangedHandler, ref this._navigateUrl, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the NavigateUrlCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand NavigateUrlCommand { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the OpenOutputFolderCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand OpenOutputFolderCommand { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the ReloadCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand ReloadCommand { get => this._reloadCommand; set => this.Set(this.PropertyChangedHandler, ref this._reloadCommand, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Url.
|
||||||
|
/// It is typed in the TextBox.
|
||||||
|
/// </summary>
|
||||||
|
public string Url { get => this.UrlEditor.Url; set => this.UrlEditor.Url = value; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the UrlEditor.
|
||||||
|
/// </summary>
|
||||||
|
public UrlEditorViewModel UrlEditor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the UrlReader.
|
||||||
|
/// </summary>
|
||||||
|
public UrlReader UrlReader { get; } = new UrlReader();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the WebBrowser.
|
||||||
|
/// </summary>
|
||||||
|
public IWebBrowser WebBrowser
|
||||||
|
{
|
||||||
|
get => _webBrowser;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (this.WebBrowser == value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_webBrowser = value;
|
||||||
|
this.InitializeHandlers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the DownloadAction.
|
||||||
|
/// </summary>
|
||||||
|
internal Action<Operation> DownloadAction { get => this.UrlEditor.DownloadAction; set => this.UrlEditor.DownloadAction = value; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Dispose.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.UrlEditor.Dispose();
|
||||||
|
this.UrlEditor.PropertyChanged -= this.OnUrlEditor_PropertyChanged;
|
||||||
|
this.UrlReader.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The InitializeHandlers.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeHandlers()
|
||||||
|
{
|
||||||
|
if (this.WebBrowser != null)
|
||||||
|
{
|
||||||
|
this.WebBrowser.DownloadHandler = this.GlobalBrowserData.DownloadHandler;
|
||||||
|
this.WebBrowser.MenuHandler = this.CefWindowData.CefContextMenuHandler;
|
||||||
|
this.WebBrowser.RequestHandler = this.CefWindowData.CefRequestHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The IsUrlValid.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
private bool IsUrlValid()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnDownload.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnDownload(object obj)
|
||||||
|
{
|
||||||
|
if (!this.IsUrlValid() || !this.UrlEditor.DownloadCommand.CanExecute(null))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.UrlEditor.DownloadCommand.Execute(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnHome.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnHome(object obj)
|
||||||
|
{
|
||||||
|
this.Url = AppEnvironment.HomeUrl;
|
||||||
|
this.NavigateUrl = this.Url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnNavigateUrl called from Button.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnNavigateUrl(object obj)
|
||||||
|
{
|
||||||
|
this.Url = VideoBrowser.Helpers.UrlHelper.GetValidUrl(this.Url);
|
||||||
|
this.NavigateUrl = this.Url;
|
||||||
|
this.CefWindowData.IsAirspaceVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnOpenOutputFolder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnOpenOutputFolder(object obj)
|
||||||
|
{
|
||||||
|
ProcessHelper.Start(this.GlobalBrowserData.Settings.OutputFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnPropertyChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender<see cref="object"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="System.ComponentModel.PropertyChangedEventArgs"/>.</param>
|
||||||
|
private void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.PropertyName)
|
||||||
|
{
|
||||||
|
case nameof(this.Url):
|
||||||
|
this.UrlReader.Url = this.Url;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(this.NavigateUrl):
|
||||||
|
this.Url = this.NavigateUrl;
|
||||||
|
this.UrlEditor.NavigateUrl = this.NavigateUrl;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnUrlEditor_PropertyChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender<see cref="object"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="System.ComponentModel.PropertyChangedEventArgs"/>.</param>
|
||||||
|
private void OnUrlEditor_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.IsMatch(nameof(this.UrlEditor.Url)))
|
||||||
|
{
|
||||||
|
this.OnPropertyChanged(nameof(this.Url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ShowMessage.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="title">The title<see cref="string"/>.</param>
|
||||||
|
/// <param name="message">The message<see cref="string"/>.</param>
|
||||||
|
private void ShowMessageAsync(string title, string message)
|
||||||
|
{
|
||||||
|
this.CefWindowData.ShowMessageAsync(title, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.ViewModels
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Views;
|
||||||
|
using VideoBrowser.Core;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
using VideoBrowser.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="WebBrowserHeaderedItemViewModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class WebBrowserHeaderedItemViewModel : TabItem
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private VideoBrowserViewModel _videoBrowserViewModel;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="WebBrowserHeaderedItemViewModel"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="globalBrowserData">The globalBrowserData<see cref="GlobalBrowserData"/>.</param>
|
||||||
|
/// <param name="cefWindowData">The cefWindowData<see cref="CefWindowData"/>.</param>
|
||||||
|
/// <param name="downloadAction">The downloadAction<see cref="Action{Operation}"/>.</param>
|
||||||
|
internal WebBrowserHeaderedItemViewModel(GlobalBrowserData globalBrowserData, CefWindowData cefWindowData, Action<Operation> downloadAction)
|
||||||
|
{
|
||||||
|
this.VideoBrowserViewModel = new VideoBrowserViewModel(globalBrowserData, cefWindowData)
|
||||||
|
{
|
||||||
|
DownloadAction = downloadAction
|
||||||
|
};
|
||||||
|
|
||||||
|
this.VideoBrowserViewModel.PropertyChanged += this.OnVideoBrowserViewModel_PropertyChanged;
|
||||||
|
this.Title = this.VideoBrowserViewModel.Header;
|
||||||
|
UIThreadHelper.Invoke(() =>
|
||||||
|
{
|
||||||
|
this.VideoBrowserView = new VideoBrowserView { DataContext = this.VideoBrowserViewModel };
|
||||||
|
this.Content = this.VideoBrowserView;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the VideoBrowserView.
|
||||||
|
/// </summary>
|
||||||
|
public VideoBrowserView VideoBrowserView { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the VideoBrowserViewModel.
|
||||||
|
/// </summary>
|
||||||
|
public VideoBrowserViewModel VideoBrowserViewModel { get => _videoBrowserViewModel; private set => this.Set(this.OnPropertyChanged, ref _videoBrowserViewModel, value); }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Dispose.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">The disposing<see cref="bool"/>.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
if (this.VideoBrowserViewModel == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.VideoBrowserViewModel.PropertyChanged -= this.OnVideoBrowserViewModel_PropertyChanged;
|
||||||
|
this.VideoBrowserViewModel.Dispose();
|
||||||
|
this.VideoBrowserViewModel = null;
|
||||||
|
this.VideoBrowserView.DataContext = null;
|
||||||
|
this.VideoBrowserView = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnVideoBrowserViewModel_PropertyChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender<see cref="object"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="PropertyChangedEventArgs"/>.</param>
|
||||||
|
private void OnVideoBrowserViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.IsMatch(nameof(this.VideoBrowserViewModel.Header)))
|
||||||
|
{
|
||||||
|
this.Title = this.VideoBrowserViewModel.Header;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,348 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.ViewModels
|
||||||
|
{
|
||||||
|
using Dragablz;
|
||||||
|
using Dragablz.Dockablz;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Controls.CefSharpBrowser.Helpers;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
using VideoBrowser.Helpers;
|
||||||
|
using VideoBrowser.Resources;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="WebBrowserTabControlViewModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class WebBrowserTabControlViewModel : INotifyPropertyChanged, IDisposable
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private static int IdCounter;
|
||||||
|
|
||||||
|
private int _selectedTabIndex;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="WebBrowserTabControlViewModel"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="globalBrowserData">The globalBrowserData<see cref="GlobalBrowserData"/>.</param>
|
||||||
|
public WebBrowserTabControlViewModel(GlobalBrowserData globalBrowserData)
|
||||||
|
{
|
||||||
|
this.GlobalBrowserData = globalBrowserData;
|
||||||
|
this.CefWindowData = new CefWindowData();
|
||||||
|
this.TabItems = new ObservableCollection<TabItem>();
|
||||||
|
this.TabItems.CollectionChanged += this.OnTabItems_CollectionChanged;
|
||||||
|
this.CreateBrowserFunc = this.CreateBrowser;
|
||||||
|
this.CefWindowData.CefRequestHandler.OpenUrlFromTabAction = this.OnOpenUrlFromTab;
|
||||||
|
this.CefWindowData.CefContextMenuHandler.OpenInNewTabAction = this.OnOpenUrlFromTab;
|
||||||
|
this.CefWindowData.CefContextMenuHandler.OpenInNewWindowAction = this.OnOpenUrlFromWindow;
|
||||||
|
this.LoadedCommand = new RelayCommand(this.OnLoaded, nameof(this.LoadedCommand));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the PropertyChanged.
|
||||||
|
/// </summary>
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
#endregion Events
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the CefWindowData.
|
||||||
|
/// </summary>
|
||||||
|
public CefWindowData CefWindowData { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the ClosingFloatingItemHandler.
|
||||||
|
/// </summary>
|
||||||
|
public ClosingFloatingItemCallback ClosingFloatingItemHandler => ClosingFloatingItemHandlerImpl;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the ClosingTabItemHandler.
|
||||||
|
/// </summary>
|
||||||
|
public ItemActionCallback ClosingTabItemHandler => ClosingTabItemHandlerImpl;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the CreateBrowserFunc.
|
||||||
|
/// </summary>
|
||||||
|
public Func<HeaderedItemViewModel> CreateBrowserFunc { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the GlobalBrowserData.
|
||||||
|
/// </summary>
|
||||||
|
public GlobalBrowserData GlobalBrowserData { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Icon.
|
||||||
|
/// </summary>
|
||||||
|
public Geometry Icon { get; set; } = Icons.SearchVideo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Id.
|
||||||
|
/// </summary>
|
||||||
|
public int Id { get; } = IdCounter++;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the InterTabClient.
|
||||||
|
/// </summary>
|
||||||
|
public IInterTabClient InterTabClient => this.GlobalBrowserData.InterTabClient;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the LoadedCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand LoadedCommand { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the SelectedTabIndex.
|
||||||
|
/// </summary>
|
||||||
|
public int SelectedTabIndex { get => _selectedTabIndex; set => this.Set(this.PropertyChanged, ref _selectedTabIndex, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the TabItems.
|
||||||
|
/// </summary>
|
||||||
|
public ObservableCollection<TabItem> TabItems { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the ToolItems.
|
||||||
|
/// </summary>
|
||||||
|
public ObservableCollection<HeaderedItemViewModel> ToolItems { get; } = new ObservableCollection<HeaderedItemViewModel>();
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The AddTab.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item<see cref="TabItem"/>.</param>
|
||||||
|
public void AddTab(TabItem item)
|
||||||
|
{
|
||||||
|
if (this.IsTabItemExist(item.Guid))
|
||||||
|
{
|
||||||
|
this.SetActiveTab(item.Guid);
|
||||||
|
Logger.Info($"Add tab canceled: Tab {item.Title} exists.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.TabItems.Add(item);
|
||||||
|
Logger.Info($"Tab {item.Title} is added.");
|
||||||
|
this.SelectedTabIndex = this.TabItems.Count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Dispose.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
var settings = this.GlobalBrowserData.BrowserSettings;
|
||||||
|
BrowserSettingsHelper.Save(settings, this);
|
||||||
|
|
||||||
|
this.TabItems.CollectionChanged -= this.OnTabItems_CollectionChanged;
|
||||||
|
this.TabItems.ClearAndDispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The IsTabItemExist.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guid">The guid<see cref="Guid"/>.</param>
|
||||||
|
/// <returns>The <see cref="bool"/>.</returns>
|
||||||
|
public bool IsTabItemExist(Guid guid)
|
||||||
|
{
|
||||||
|
return this.TabItems.Any((o) => o.Guid == guid) && guid != Guid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="string"/>.</returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var message = $"{nameof(WebBrowserTabControlViewModel)} {this.Id}";
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The SetActiveTab.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guid">The guid<see cref="Guid"/>.</param>
|
||||||
|
internal void SetActiveTab(Guid guid)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < this.TabItems.Count; i++)
|
||||||
|
{
|
||||||
|
if (this.TabItems[i].Guid == guid)
|
||||||
|
{
|
||||||
|
this.SelectedTabIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Callback to handle floating toolbar/MDI window closing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">The args<see cref="ItemActionCallbackArgs{Layout}"/>.</param>
|
||||||
|
private static void ClosingFloatingItemHandlerImpl(ItemActionCallbackArgs<Layout> args)
|
||||||
|
{
|
||||||
|
//in here you can dispose stuff or cancel the close
|
||||||
|
|
||||||
|
//here's your view model:
|
||||||
|
if (args.DragablzItem.DataContext is IDisposable disposable)
|
||||||
|
{
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Callback to handle tab closing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">The args<see cref="ItemActionCallbackArgs{TabablzControl}"/>.</param>
|
||||||
|
private static void ClosingTabItemHandlerImpl(ItemActionCallbackArgs<TabablzControl> args)
|
||||||
|
{
|
||||||
|
//in here you can dispose stuff or cancel the close
|
||||||
|
|
||||||
|
//here's your view model:
|
||||||
|
var viewModel = args.DragablzItem.DataContext as HeaderedItemViewModel;
|
||||||
|
if (viewModel.Content is FrameworkElement element && element.DataContext is IDisposable disposable)
|
||||||
|
{
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
//here's how you can cancel stuff:
|
||||||
|
//args.Cancel();
|
||||||
|
System.Diagnostics.Debug.Assert(viewModel != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CreateBrowser.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="HeaderedItemViewModel"/>.</returns>
|
||||||
|
private HeaderedItemViewModel CreateBrowser()
|
||||||
|
{
|
||||||
|
var model = new WebBrowserHeaderedItemViewModel(this.GlobalBrowserData, this.CefWindowData, null);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnLoaded.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnLoaded(object obj)
|
||||||
|
{
|
||||||
|
if (!this.GlobalBrowserData.IsSettingsLoaded)
|
||||||
|
{
|
||||||
|
this.GlobalBrowserData.IsSettingsLoaded = true;
|
||||||
|
var settings = this.GlobalBrowserData.BrowserSettings;
|
||||||
|
var tabSettings = settings.TabSettingModels;
|
||||||
|
if (tabSettings.Any())
|
||||||
|
{
|
||||||
|
var firstTab = (this.TabItems.First().Content as FrameworkElement).DataContext as VideoBrowserViewModel;
|
||||||
|
firstTab.NavigateUrl = tabSettings.First().Url;
|
||||||
|
firstTab.Header = tabSettings.First().Title;
|
||||||
|
for (var i = 1; i < tabSettings.Count; i++)
|
||||||
|
{
|
||||||
|
var tabItemSetting = tabSettings[i];
|
||||||
|
this.OnOpenUrlFromTab(tabItemSetting.Url, tabItemSetting.Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
this.SelectedTabIndex = settings.SelectedTabSettingIndex;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var downloadItem in settings.DownloadItems)
|
||||||
|
{
|
||||||
|
if (System.IO.File.Exists(downloadItem.OutputPath))
|
||||||
|
{
|
||||||
|
this.GlobalBrowserData.DownloadItemModels.Add(downloadItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnOpenUrlFromTab.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">The url<see cref="string"/>.</param>
|
||||||
|
private void OnOpenUrlFromTab(string url)
|
||||||
|
{
|
||||||
|
OnOpenUrlFromTab(url, string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnOpenUrlFromTab.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">The url<see cref="string"/>.</param>
|
||||||
|
/// <param name="title">The title<see cref="string"/>.</param>
|
||||||
|
private void OnOpenUrlFromTab(string url, string title)
|
||||||
|
{
|
||||||
|
UIThreadHelper.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
var browser = this.CreateBrowserFunc() as WebBrowserHeaderedItemViewModel;
|
||||||
|
browser.VideoBrowserViewModel.NavigateUrl = url;
|
||||||
|
if (!string.IsNullOrEmpty(title))
|
||||||
|
{
|
||||||
|
browser.VideoBrowserViewModel.Header = title;
|
||||||
|
}
|
||||||
|
this.AddTab(browser);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnOpenUrlFromWindow.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">The url<see cref="string"/>.</param>
|
||||||
|
private void OnOpenUrlFromWindow(string url)
|
||||||
|
{
|
||||||
|
var browser = this.CreateBrowserFunc() as WebBrowserHeaderedItemViewModel;
|
||||||
|
browser.VideoBrowserViewModel.NavigateUrl = url;
|
||||||
|
UIThreadHelper.Invoke(() =>
|
||||||
|
{
|
||||||
|
var (Window, TabablzControl) = this.GlobalBrowserData.InterTabClient.CreateWindow();
|
||||||
|
Window.Show();
|
||||||
|
if (TabablzControl.ItemsSource is ICollection<TabItem> items)
|
||||||
|
{
|
||||||
|
items.Add(browser);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnTabItems_CollectionChanged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender<see cref="object"/>.</param>
|
||||||
|
/// <param name="e">The e<see cref="NotifyCollectionChangedEventArgs"/>.</param>
|
||||||
|
private void OnTabItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Action == NotifyCollectionChangedAction.Add)
|
||||||
|
{
|
||||||
|
foreach (var item in e.NewItems)
|
||||||
|
{
|
||||||
|
if (item is WebBrowserHeaderedItemViewModel browserTabItem)
|
||||||
|
{
|
||||||
|
browserTabItem.VideoBrowserViewModel.CefWindowData = this.CefWindowData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.ViewModels
|
||||||
|
{
|
||||||
|
using Dragablz;
|
||||||
|
using System;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using VideoBrowser.Common;
|
||||||
|
using VideoBrowser.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="WebBrowserTabHeaderViewModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class WebBrowserTabHeaderViewModel : NotifyPropertyChanged
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private string _header;
|
||||||
|
|
||||||
|
private ImageSource _image;
|
||||||
|
|
||||||
|
private bool _isSelected;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="WebBrowserTabHeaderViewModel"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public WebBrowserTabHeaderViewModel()
|
||||||
|
{
|
||||||
|
this.MouseUpCommand = new RelayCommand(this.OnMouseUp, nameof(this.MouseUpCommand));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Header.
|
||||||
|
/// </summary>
|
||||||
|
public string Header { get => _header; set => this.Set(this.PropertyChangedHandler, ref _header, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Image.
|
||||||
|
/// </summary>
|
||||||
|
public ImageSource Image { get => _image; set => this.Set(this.PropertyChangedHandler, ref _image, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether IsSelected.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSelected { get => _isSelected; set => this.Set(this.PropertyChangedHandler, ref _isSelected, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the MouseUpCommand.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand MouseUpCommand { get; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnMouseUp.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj<see cref="object"/>.</param>
|
||||||
|
private void OnMouseUp(object obj)
|
||||||
|
{
|
||||||
|
Logger.Info($"Middle Mouse clicked on a browser tab to close it.");
|
||||||
|
var (_, args, commandParameter) = (ValueTuple<object, EventArgs, object>)obj;
|
||||||
|
if (args is MouseButtonEventArgs mouseEventArgs && mouseEventArgs.ChangedButton == MouseButton.Middle)
|
||||||
|
{
|
||||||
|
var dragablzItem = commandParameter as System.Windows.FrameworkElement;
|
||||||
|
var closeCommand = TabablzControl.CloseItemCommand;
|
||||||
|
if (closeCommand != null && closeCommand.CanExecute(commandParameter, dragablzItem))
|
||||||
|
{
|
||||||
|
closeCommand.Execute(dragablzItem, dragablzItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<Window
|
||||||
|
x:Class="VideoBrowser.Controls.CefSharpBrowser.Views.DefaultTabHostWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:viewmodels="clr-namespace:VideoBrowser.Controls.CefSharpBrowser.ViewModels"
|
||||||
|
xmlns:views="clr-namespace:VideoBrowser.Controls.CefSharpBrowser.Views"
|
||||||
|
d:DataContext="{d:DesignInstance viewmodels:DefaultTabHostViewModel}"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<views:WebBrowserTabControlView x:Name="WebBrowserTabControlView" DataContext="{Binding WebBrowserTabControlViewModel}" />
|
||||||
|
</Window>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for DefaultTabHostWindow.xaml.
|
||||||
|
/// </summary>
|
||||||
|
public partial class DefaultTabHostWindow
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DefaultTabHostWindow"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public DefaultTabHostWindow()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="VideoBrowser.Controls.CefSharpBrowser.Views.SettingsView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:viewmodels="clr-namespace:VideoBrowser.ViewModels"
|
||||||
|
d:DataContext="{d:DesignInstance viewmodels:SettingsViewModel}"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
Background="WhiteSmoke"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="../../../Resources/IconsResource.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
<Style BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" TargetType="Button">
|
||||||
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
|
<Setter Property="Margin" Value="2" />
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Border
|
||||||
|
Margin="32"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Background="White">
|
||||||
|
<Border.Effect>
|
||||||
|
<DropShadowEffect
|
||||||
|
BlurRadius="10"
|
||||||
|
Opacity="0.3"
|
||||||
|
ShadowDepth="3" />
|
||||||
|
</Border.Effect>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label
|
||||||
|
Grid.Row="0"
|
||||||
|
Height="50"
|
||||||
|
Padding="16,5,5,5"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
Background="RoyalBlue"
|
||||||
|
Content="Settings"
|
||||||
|
FontSize="16"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="White" />
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="1"
|
||||||
|
Width="500"
|
||||||
|
Margin="24">
|
||||||
|
<TextBlock Text="Output Path" />
|
||||||
|
<StackPanel Margin="0,8,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{Binding OutputFolder}" />
|
||||||
|
<Button
|
||||||
|
Margin="8,0,0,0"
|
||||||
|
Command="{Binding GetFolderCommand}"
|
||||||
|
CommandParameter="{Binding RelativeSource={RelativeSource Self}}">
|
||||||
|
<Path Style="{StaticResource VideoFolder}" />
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Views
|
||||||
|
{
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for SettingsView.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class SettingsView : UserControl
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SettingsView"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public SettingsView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="VideoBrowser.Controls.CefSharpBrowser.Views.VideoBrowserView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:cefSharpViews="clr-namespace:VideoBrowser.Controls.CefSharpBrowser.Views"
|
||||||
|
xmlns:cefsharpbrowser="clr-namespace:VideoBrowser.Controls.CefSharpBrowser"
|
||||||
|
xmlns:converters="clr-namespace:VideoBrowser.Converters"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:viewmodels="clr-namespace:VideoBrowser.Controls.CefSharpBrowser.ViewModels"
|
||||||
|
xmlns:views="clr-namespace:VideoBrowser.Views"
|
||||||
|
d:DataContext="{d:DesignInstance viewmodels:VideoBrowserViewModel}"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="../../../Resources/IconsResource.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
<converters:BoolToVisibilityConverter
|
||||||
|
x:Key="InverseBoolToVisibilityConverter"
|
||||||
|
FalseValue="Visible"
|
||||||
|
TrueValue="Collapsed" />
|
||||||
|
<converters:BoolToBoolConverter
|
||||||
|
x:Key="InverseBoolToBoolConverter"
|
||||||
|
FalseValue="True"
|
||||||
|
TrueValue="False" />
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<!-- Browser Main Toolbar -->
|
||||||
|
<Grid
|
||||||
|
Grid.Row="0"
|
||||||
|
Margin="0,0,0,4"
|
||||||
|
Panel.ZIndex="999"
|
||||||
|
Visibility="{Binding CefWindowData.IsFullScreen, Mode=OneWay, Converter={StaticResource InverseBoolToVisibilityConverter}}">
|
||||||
|
<Grid.Resources>
|
||||||
|
<Style BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" TargetType="Button">
|
||||||
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
|
<Setter Property="Width" Value="24" />
|
||||||
|
<Setter Property="Height" Value="24" />
|
||||||
|
<Setter Property="Margin" Value="2" />
|
||||||
|
<Setter Property="Padding" Value="0" />
|
||||||
|
</Style>
|
||||||
|
</Grid.Resources>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<!-- Left side buttons -->
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="0"
|
||||||
|
Height="32"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Button Command="{Binding BackwardCommand}" ToolTip="Go back to previous visited site">
|
||||||
|
<Path Style="{StaticResource Back}" />
|
||||||
|
</Button>
|
||||||
|
<Button Command="{Binding ForwardCommand}" ToolTip="Go forward to previous visited site">
|
||||||
|
<Path Style="{StaticResource Forward}" />
|
||||||
|
</Button>
|
||||||
|
<Button Command="{Binding ReloadCommand}" ToolTip="Refresh this site">
|
||||||
|
<Path Style="{StaticResource Reload}" />
|
||||||
|
</Button>
|
||||||
|
<Button Command="{Binding HomeCommand}" ToolTip="Go home site for newest information">
|
||||||
|
<Path Style="{StaticResource Home}" />
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
<!-- URL TextBox -->
|
||||||
|
<Grid x:Name="UrlEditorGrid" Grid.Column="1">
|
||||||
|
<Canvas>
|
||||||
|
<views:UrlEditorView
|
||||||
|
x:Name="UrlEditorView"
|
||||||
|
Width="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualWidth, Mode=OneWay}"
|
||||||
|
Background="White"
|
||||||
|
DataContext="{Binding UrlEditor}" />
|
||||||
|
</Canvas>
|
||||||
|
</Grid>
|
||||||
|
<!-- Right side buttons -->
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="2"
|
||||||
|
Height="32"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Button
|
||||||
|
Command="{Binding DownloadCommand}"
|
||||||
|
IsEnabled="{Binding UrlEditor.IsDownloadable}"
|
||||||
|
ToolTip="Download the current video">
|
||||||
|
<Path Style="{StaticResource Download}" />
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
<!-- Add in buttons -->
|
||||||
|
<ItemsControl
|
||||||
|
Grid.Column="3"
|
||||||
|
Height="32"
|
||||||
|
ItemsSource="{Binding AddInButtons}">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Button
|
||||||
|
Command="{Binding Command}"
|
||||||
|
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=cefSharpViews:WebBrowserTabControlView}, Path=DataContext}"
|
||||||
|
IsEnabled="{Binding IsEnabled}"
|
||||||
|
ToolTip="{Binding ToolTip}">
|
||||||
|
<Path Data="{Binding Icon}" Style="{StaticResource IconPathButtonBaseStyle}" />
|
||||||
|
</Button>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</Grid>
|
||||||
|
<cefsharpbrowser:CefSharpBrowser
|
||||||
|
x:Name="CefSharpBrowserControl"
|
||||||
|
Title="{Binding Header}"
|
||||||
|
Grid.Row="1"
|
||||||
|
BackwardCommand="{Binding BackwardCommand, Mode=OneWayToSource}"
|
||||||
|
ForwardCommand="{Binding ForwardCommand, Mode=OneWayToSource}"
|
||||||
|
IsAirspaceVisible="{Binding CefWindowData.IsAirspaceVisible}"
|
||||||
|
IsFullScreenCommand="{Binding CefWindowData.IsFullScreenCommand, Mode=OneWay}"
|
||||||
|
ReloadCommand="{Binding ReloadCommand, Mode=OneWayToSource}"
|
||||||
|
Url="{Binding NavigateUrl}"
|
||||||
|
WebBrowser="{Binding WebBrowser, Mode=OneWayToSource}" />
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Views
|
||||||
|
{
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for VideoBrowserView.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class VideoBrowserView : UserControl
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="VideoBrowserView"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public VideoBrowserView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="VideoBrowser.Controls.CefSharpBrowser.Views.WebBrowserTabControlView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:dockablz="http://dragablz.net/winfx/xaml/dockablz"
|
||||||
|
xmlns:dragablz="http://dragablz.net/winfx/xaml/dragablz"
|
||||||
|
xmlns:extension="clr-namespace:VideoBrowser.Extensions"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:viewmodels="clr-namespace:VideoBrowser.Controls.CefSharpBrowser.ViewModels"
|
||||||
|
d:DataContext="{d:DesignInstance viewmodels:WebBrowserTabControlViewModel}"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
Loaded="{extension:EventBinding Command={Binding LoadedCommand}}"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<DataTemplate DataType="{x:Type dragablz:HeaderedItemViewModel}">
|
||||||
|
<ContentControl
|
||||||
|
Margin="4"
|
||||||
|
Content="{Binding Content}"
|
||||||
|
FontSize="14" />
|
||||||
|
</DataTemplate>
|
||||||
|
<dragablz:InterTabController
|
||||||
|
x:Key="InterTabController"
|
||||||
|
x:Shared="False"
|
||||||
|
InterTabClient="{Binding InterTabClient}"
|
||||||
|
Partition="2AE89D18-F236-4D20-9605-6C03319038E6" />
|
||||||
|
<Style x:Key="TabablzControlStyle" TargetType="{x:Type dragablz:TabablzControl}">
|
||||||
|
<Setter Property="ItemsSource" Value="{Binding TabItems}" />
|
||||||
|
<Setter Property="ClosingItemCallback" Value="{Binding ClosingTabItemHandler}" />
|
||||||
|
<Setter Property="ShowDefaultAddButton" Value="True" />
|
||||||
|
<Setter Property="ShowDefaultCloseButton" Value="True" />
|
||||||
|
<Setter Property="AdjacentHeaderItemOffset" Value="-10" />
|
||||||
|
<Setter Property="ItemContainerStyle" Value="{StaticResource TrapezoidDragableTabItemStyle}" />
|
||||||
|
<Setter Property="HeaderMemberPath" Value="Header" />
|
||||||
|
<Setter Property="InterTabController" Value="{StaticResource InterTabController}" />
|
||||||
|
<Setter Property="Margin" Value="0,8,0,0" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=(dockablz:Layout.IsTopLeftItem)}" Value="True">
|
||||||
|
<Setter Property="HeaderPrefixContent" Value="{StaticResource WindowIcon}" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<dockablz:Layout
|
||||||
|
Name="RootLayout"
|
||||||
|
ClosingFloatingItemCallback="{Binding ClosingFloatingItemHandler}"
|
||||||
|
FloatingItemHeaderMemberPath="Header"
|
||||||
|
FloatingItemsContainerMargin="0 2 0 0"
|
||||||
|
FloatingItemsSource="{Binding ToolItems}"
|
||||||
|
IsFloatDropZoneEnabled="True"
|
||||||
|
Partition="2AE89D18-F236-4D20-9605-6C03319038E6">
|
||||||
|
<!-- branch template lets dragablz create a new tab control after a window is split via docking -->
|
||||||
|
<dockablz:Layout.BranchTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<dragablz:TabablzControl Style="{StaticResource TabablzControlStyle}">
|
||||||
|
<dragablz:TabablzControl.InterTabController>
|
||||||
|
<dragablz:InterTabController InterTabClient="{Binding InterTabClient}" Partition="2AE89D18-F236-4D20-9605-6C03319038E6" />
|
||||||
|
</dragablz:TabablzControl.InterTabController>
|
||||||
|
</dragablz:TabablzControl>
|
||||||
|
</DataTemplate>
|
||||||
|
</dockablz:Layout.BranchTemplate>
|
||||||
|
<dragablz:TabablzControl
|
||||||
|
x:Name="InitialTabablzControl"
|
||||||
|
AddLocationHint="After"
|
||||||
|
FixedHeaderCount="1"
|
||||||
|
NewItemFactory="{Binding CreateBrowserFunc}"
|
||||||
|
SelectedIndex="{Binding SelectedTabIndex}"
|
||||||
|
Style="{StaticResource TabablzControlStyle}">
|
||||||
|
<dragablz:TabablzControl.InterTabController>
|
||||||
|
<dragablz:InterTabController InterTabClient="{Binding InterTabClient}" Partition="2AE89D18-F236-4D20-9605-6C03319038E6" />
|
||||||
|
</dragablz:TabablzControl.InterTabController>
|
||||||
|
</dragablz:TabablzControl>
|
||||||
|
</dockablz:Layout>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for WebBrowserTabControlView.xaml.
|
||||||
|
/// </summary>
|
||||||
|
public partial class WebBrowserTabControlView
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="WebBrowserTabControlView"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public WebBrowserTabControlView()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="VideoBrowser.Controls.CefSharpBrowser.Views.WebBrowserTabHeaderView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:dragablz="http://dragablz.net/winfx/xaml/dragablz"
|
||||||
|
xmlns:extension="clr-namespace:VideoBrowser.Extensions"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:viewmodels="clr-namespace:VideoBrowser.Controls.CefSharpBrowser.ViewModels"
|
||||||
|
d:DataContext="{d:DesignInstance viewmodels:WebBrowserTabHeaderViewModel}"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<Style x:Key="InvisibleThumbStyle" TargetType="{x:Type Thumb}">
|
||||||
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate>
|
||||||
|
<Grid Background="{TemplateBinding Background}" />
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Image
|
||||||
|
Margin="2,0,2,0"
|
||||||
|
Source="{Binding Image}"
|
||||||
|
Stretch="Uniform" />
|
||||||
|
<Grid>
|
||||||
|
<TextBlock Width="100" Text="{Binding Header}" />
|
||||||
|
<!-- you should provide your own Thumb, which will be used to monitor dragging -->
|
||||||
|
<Thumb
|
||||||
|
dragablz:DragablzItem.IsCustomThumb="True"
|
||||||
|
MouseUp="{extension:EventBinding Command={Binding MouseUpCommand},
|
||||||
|
CommandParameter={Binding RelativeSource={RelativeSource Self}}}"
|
||||||
|
Style="{DynamicResource InvisibleThumbStyle}"
|
||||||
|
ToolTip="{Binding Header}" />
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace VideoBrowser.Controls.CefSharpBrowser.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for WebBrowserTabHeaderView.xaml.
|
||||||
|
/// </summary>
|
||||||
|
public partial class WebBrowserTabHeaderView
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="WebBrowserTabHeaderView"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public WebBrowserTabHeaderView()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
}
|
||||||
|
}
|
||||||
376
VideoBrowser/Converters/BoolToValueConverter.cs
Normal file
376
VideoBrowser/Converters/BoolToValueConverter.cs
Normal file
@@ -0,0 +1,376 @@
|
|||||||
|
namespace VideoBrowser.Converters
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToBoolConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToBoolConverter : BoolToValueConverter<bool>
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private static readonly Lazy<ValueConverter> _instance = new Lazy<ValueConverter>(() => new BoolToBoolConverter());
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BoolToBoolConverter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public BoolToBoolConverter()
|
||||||
|
{
|
||||||
|
TrueValue = false;
|
||||||
|
FalseValue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Instance
|
||||||
|
/// </summary>
|
||||||
|
public static ValueConverter Instance
|
||||||
|
{
|
||||||
|
get { return _instance.Value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToBrushConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToBrushConverter : BoolToValueConverter<Brush>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToByteConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToByteConverter : BoolToValueConverter<Byte>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToColorConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToColorConverter : BoolToValueConverter<Color>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToDecimalConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToDecimalConverter : BoolToValueConverter<Decimal>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToDoubleConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToDoubleConverter : BoolToValueConverter<Double>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToHorizontalAlignmentConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToHorizontalAlignmentConverter : BoolToValueConverter<HorizontalAlignment>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToInt16Converter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToInt16Converter : BoolToValueConverter<Int16>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToInt32Converter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToInt32Converter : BoolToValueConverter<Int32>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToInt64Converter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToInt64Converter : BoolToValueConverter<Int64>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToObjectConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToObjectConverter : BoolToValueConverter<Object>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToPointConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToPointConverter : BoolToValueConverter<Point>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToRectConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToRectConverter : BoolToValueConverter<Rect>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToSByteConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToSByteConverter : BoolToValueConverter<SByte>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToSingleConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToSingleConverter : BoolToValueConverter<Single>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToStringConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToStringConverter : BoolToValueConverter<String>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToStyleConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToStyleConverter : BoolToValueConverter<Style>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToThicknessConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToThicknessConverter : BoolToValueConverter<Thickness>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToUInt16Converter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToUInt16Converter : BoolToValueConverter<UInt16>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToUInt32Converter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToUInt32Converter : BoolToValueConverter<UInt32>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToUInt64Converter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToUInt64Converter : BoolToValueConverter<UInt64>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToValueConverter{T}" />
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public class BoolToValueConverter<T> : ValueConverter
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the FalseValue
|
||||||
|
/// </summary>
|
||||||
|
public T FalseValue { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the TrueValue
|
||||||
|
/// </summary>
|
||||||
|
public T TrueValue { get; set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Convert
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value<see cref="object"/></param>
|
||||||
|
/// <param name="targetType">The targetType<see cref="Type"/></param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/></param>
|
||||||
|
/// <param name="culture">The culture<see cref="System.Globalization.CultureInfo"/></param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
return this.FalseValue;
|
||||||
|
else
|
||||||
|
return (bool)value ? this.TrueValue : this.FalseValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ConvertBack
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value<see cref="object"/></param>
|
||||||
|
/// <param name="targetType">The targetType<see cref="Type"/></param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/></param>
|
||||||
|
/// <param name="culture">The culture<see cref="System.Globalization.CultureInfo"/></param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
return value != null ? value.Equals(this.TrueValue) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToVerticalAlignmentConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToVerticalAlignmentConverter : BoolToValueConverter<VerticalAlignment>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="BoolToVisibilityConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class BoolToVisibilityConverter : BoolToValueConverter<Visibility>
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private static readonly Lazy<ValueConverter> _trueIsVisibleConverter = new Lazy<ValueConverter>(() => new BoolToVisibilityConverter() { TrueValue = Visibility.Visible, FalseValue = Visibility.Collapsed });
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the TrueIsVisibleConverter
|
||||||
|
/// </summary>
|
||||||
|
public static ValueConverter TrueIsVisibleConverter
|
||||||
|
{
|
||||||
|
get { return _trueIsVisibleConverter.Value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="EqualsToBoolConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class EqualsToBoolConverter : BoolToValueConverter<String>
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the CompareValue
|
||||||
|
/// </summary>
|
||||||
|
public string CompareValue { get; set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Convert
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value<see cref="object"/></param>
|
||||||
|
/// <param name="targetType">The targetType<see cref="Type"/></param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/></param>
|
||||||
|
/// <param name="culture">The culture<see cref="System.Globalization.CultureInfo"/></param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
return this.FalseValue;
|
||||||
|
else if (CompareValue != null)
|
||||||
|
return value.ToString() == CompareValue ? this.TrueValue : this.FalseValue;
|
||||||
|
return System.Convert.ToBoolean(value) ? this.TrueValue : this.FalseValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="EqualsToBrushConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class EqualsToBrushConverter : BoolToValueConverter<Brush>
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the CompareValue
|
||||||
|
/// </summary>
|
||||||
|
public string CompareValue { get; set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Convert
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value<see cref="object"/></param>
|
||||||
|
/// <param name="targetType">The targetType<see cref="Type"/></param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/></param>
|
||||||
|
/// <param name="culture">The culture<see cref="System.Globalization.CultureInfo"/></param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
return this.FalseValue;
|
||||||
|
else if (CompareValue != null)
|
||||||
|
return String.Equals(value.ToString(), CompareValue, StringComparison.CurrentCultureIgnoreCase) ? this.TrueValue : this.FalseValue;
|
||||||
|
return System.Convert.ToBoolean(value) ? this.TrueValue : this.FalseValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="EqualsToVisibilityConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class EqualsToVisibilityConverter : BoolToValueConverter<Visibility>
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the CompareValue
|
||||||
|
/// </summary>
|
||||||
|
public string CompareValue { get; set; }
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Convert
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value<see cref="object"/></param>
|
||||||
|
/// <param name="targetType">The targetType<see cref="Type"/></param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/></param>
|
||||||
|
/// <param name="culture">The culture<see cref="System.Globalization.CultureInfo"/></param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
return this.FalseValue;
|
||||||
|
else if (CompareValue != null)
|
||||||
|
return value.ToString() == CompareValue ? this.TrueValue : this.FalseValue;
|
||||||
|
return System.Convert.ToBoolean(value) ? this.TrueValue : this.FalseValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
51
VideoBrowser/Converters/MultiplyConverter.cs
Normal file
51
VideoBrowser/Converters/MultiplyConverter.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
namespace VideoBrowser.Converters
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="MultiplyConverter" />.
|
||||||
|
/// </summary>
|
||||||
|
public class MultiplyConverter : IMultiValueConverter
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Convert.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="values">The values<see cref="object[]"/>.</param>
|
||||||
|
/// <param name="targetType">The targetType<see cref="Type"/>.</param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/>.</param>
|
||||||
|
/// <param name="culture">The culture<see cref="CultureInfo"/>.</param>
|
||||||
|
/// <returns>The <see cref="object"/>.</returns>
|
||||||
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
var result = 1.0;
|
||||||
|
for (var i = 0; i < values.Length; i++)
|
||||||
|
{
|
||||||
|
if (values[i] is double)
|
||||||
|
{
|
||||||
|
result *= (double)values[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ConvertBack.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value<see cref="object"/>.</param>
|
||||||
|
/// <param name="targetTypes">The targetTypes<see cref="Type[]"/>.</param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/>.</param>
|
||||||
|
/// <param name="culture">The culture<see cref="CultureInfo"/>.</param>
|
||||||
|
/// <returns>The <see cref="object[]"/>.</returns>
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new Exception("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
226
VideoBrowser/Converters/ValueConverter.cs
Normal file
226
VideoBrowser/Converters/ValueConverter.cs
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
namespace VideoBrowser.Converters
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Markup;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="ValueConverter" />
|
||||||
|
/// </summary>
|
||||||
|
public class ValueConverter : MarkupExtension, IValueConverter, IMultiValueConverter
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ValueConverter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
protected ValueConverter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public object Convert(object value)
|
||||||
|
{
|
||||||
|
return this.Convert(value, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="parameter">The parameter.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public object Convert(object value, object parameter)
|
||||||
|
{
|
||||||
|
return this.Convert(value, null, parameter, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value produced by the <see cref="Binding" /> source.</param>
|
||||||
|
/// <param name="targetType">The type of the <see cref="Binding" /> target property.</param>
|
||||||
|
/// <param name="parameter">The converter parameter to use.</param>
|
||||||
|
/// <param name="culture">The culture to use in the converter.</param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public object ConvertBack(object value)
|
||||||
|
{
|
||||||
|
return this.ConvertBack(value, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="parameter">The parameter.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public object ConvertBack(object value, object parameter)
|
||||||
|
{
|
||||||
|
return this.ConvertBack(value, null, parameter, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value that is produced by the <see cref="Binding" /> target.</param>
|
||||||
|
/// <param name="targetType">The type to convert to.</param>
|
||||||
|
/// <param name="parameter">The converter parameter to use.</param>
|
||||||
|
/// <param name="culture">The culture to use in the converter.</param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a set of values to a single value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="values">The values.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public object MultiConvert(object[] values)
|
||||||
|
{
|
||||||
|
return this.MultiConvert(values, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a set of values to a single value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="values">The values.</param>
|
||||||
|
/// <param name="parameter">The parameter.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public object MultiConvert(object[] values, object parameter)
|
||||||
|
{
|
||||||
|
return this.MultiConvert(values, null, parameter, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts source values to a value for the <see cref="Binding" /> target. The data binding engine calls this method when it propagates the values from source bindings to the <see cref="Binding" /> target.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="values">The array of values that the source bindings in the <see cref="T:System.Windows.Data.MultiBinding"/> produces. The value <see cref="F:System.Windows.DependencyProperty.UnsetValue"/> indicates that the source binding has no value to provide for conversion.</param>
|
||||||
|
/// <param name="targetType">The type of the <see cref="Binding" /> target property.</param>
|
||||||
|
/// <param name="parameter">The converter parameter to use.</param>
|
||||||
|
/// <param name="culture">The culture to use in the converter.</param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
public virtual object MultiConvert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a set of values to a single value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public object[] MultiConvertBack(object value)
|
||||||
|
{
|
||||||
|
return this.MultiConvertBack(value, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a set of values to a single value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="parameter">The parameter.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public object[] MultiConvertBack(object value, object parameter)
|
||||||
|
{
|
||||||
|
return this.MultiConvertBack(value, null, parameter, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="Binding" /> target value to the source binding values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value that the <see cref="Binding" /> target produces.</param>
|
||||||
|
/// <param name="targetTypes">The array of types to convert to. The array length indicates the number and types of values that are suggested for the method to return.</param>
|
||||||
|
/// <param name="parameter">The converter parameter to use.</param>
|
||||||
|
/// <param name="culture">The culture to use in the converter.</param>
|
||||||
|
/// <returns>The <see cref="object[]"/></returns>
|
||||||
|
public virtual object[] MultiConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns this instace.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serviceProvider">Object that can provide services for the markup extension.</param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
public sealed override object ProvideValue(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Convert
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value<see cref="object"/></param>
|
||||||
|
/// <param name="targetType">The targetType<see cref="Type"/></param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/></param>
|
||||||
|
/// <param name="culture">The culture<see cref="CultureInfo"/></param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return this.Convert(value, targetType, parameter, culture);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Convert
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="values">The values<see cref="object[]"/></param>
|
||||||
|
/// <param name="targetType">The targetType<see cref="Type"/></param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/></param>
|
||||||
|
/// <param name="culture">The culture<see cref="CultureInfo"/></param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
object IMultiValueConverter.Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return this.MultiConvert(values, targetType, parameter, culture);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ConvertBack
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value<see cref="object"/></param>
|
||||||
|
/// <param name="targetType">The targetType<see cref="Type"/></param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/></param>
|
||||||
|
/// <param name="culture">The culture<see cref="CultureInfo"/></param>
|
||||||
|
/// <returns>The <see cref="object"/></returns>
|
||||||
|
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return this.ConvertBack(value, targetType, parameter, culture);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ConvertBack
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value<see cref="object"/></param>
|
||||||
|
/// <param name="targetTypes">The targetTypes<see cref="Type[]"/></param>
|
||||||
|
/// <param name="parameter">The parameter<see cref="object"/></param>
|
||||||
|
/// <param name="culture">The culture<see cref="CultureInfo"/></param>
|
||||||
|
/// <returns>The <see cref="object[]"/></returns>
|
||||||
|
object[] IMultiValueConverter.ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return this.MultiConvertBack(value, targetTypes, parameter, culture);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user