Compare commits
8 Commits
f767fe6e35
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 97951ac6f0 | |||
| 0abb8467f2 | |||
| fc46e56b82 | |||
| 8fe93de673 | |||
| c8c674dd1c | |||
| 72bd778d56 | |||
|
|
82fcaaaf90 | ||
|
|
2236c19c07 |
6
HorseRacingPredictor/HorseRacingPredictor/App.xaml
Normal file
6
HorseRacingPredictor/HorseRacingPredictor/App.xaml
Normal file
@@ -0,0 +1,6 @@
|
||||
<Application x:Class="HorseRacingPredictor.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources />
|
||||
</Application>
|
||||
8
HorseRacingPredictor/HorseRacingPredictor/App.xaml.cs
Normal file
8
HorseRacingPredictor/HorseRacingPredictor/App.xaml.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace HorseRacingPredictor
|
||||
{
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\Microsoft.ML.FastTree.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.FastTree.props" Condition="Exists('..\packages\Microsoft.ML.FastTree.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.FastTree.props')" />
|
||||
<Import Project="..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.props" Condition="Exists('..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.props')" />
|
||||
<Import Project="..\packages\Microsoft.ML.CpuMath.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.CpuMath.props" Condition="Exists('..\packages\Microsoft.ML.CpuMath.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.CpuMath.props')" />
|
||||
<Import Project="..\packages\Microsoft.ML.FastTree.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.FastTree.props" Condition="Exists('..\packages\Microsoft.ML.FastTree.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.FastTree.props')" />
|
||||
<Import Project="..\packages\Microsoft.ML.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.props" Condition="Exists('..\packages\Microsoft.ML.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.props')" />
|
||||
<Import Project="..\packages\Microsoft.ML.CpuMath.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.CpuMath.props" Condition="Exists('..\packages\Microsoft.ML.CpuMath.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.CpuMath.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -13,6 +13,7 @@
|
||||
<AssemblyName>HorseRacingPredictor</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
<NuGetPackageImportStamp>
|
||||
@@ -43,9 +44,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
@@ -53,79 +52,51 @@
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="CsvHelper, Version=33.0.0.0, Culture=neutral, PublicKeyToken=8c4959082be5c823, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CsvHelper.33.0.1\lib\net48\CsvHelper.dll</HintPath>
|
||||
<Reference Include="CsvHelper, Version=33.0.0.0, Culture=neutral, PublicKeyToken=8c4a6d608ce8f59c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CsvHelper.33.1.0\lib\net48\CsvHelper.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Dapper, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Dapper.2.1.66\lib\net461\Dapper.dll</HintPath>
|
||||
<Reference Include="Microsoft.Web.WebView2.Core, Version=1.0.3800.47, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.3800.47\lib\net462\Microsoft.Web.WebView2.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.10.0.0-preview.4.25258.110\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||
<Reference Include="Microsoft.Web.WebView2.Wpf, Version=1.0.3800.47, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.3800.47\lib\net462\Microsoft.Web.WebView2.Wpf.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bcl.HashCode, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bcl.HashCode.6.0.0\lib\net462\Microsoft.Bcl.HashCode.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bcl.Numerics, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bcl.Numerics.10.0.0-preview.4.25258.110\lib\net462\Microsoft.Bcl.Numerics.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ML.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\lib\netstandard2.0\Microsoft.ML.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ML.CpuMath, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ML.CpuMath.5.0.0-preview.1.25127.4\lib\netstandard2.0\Microsoft.ML.CpuMath.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ML.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\lib\netstandard2.0\Microsoft.ML.Data.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ML.DataView, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ML.DataView.5.0.0-preview.1.25127.4\lib\netstandard2.0\Microsoft.ML.DataView.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ML.FastTree, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ML.FastTree.5.0.0-preview.1.25127.4\lib\netstandard2.0\Microsoft.ML.FastTree.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ML.KMeansClustering, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\lib\netstandard2.0\Microsoft.ML.KMeansClustering.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ML.PCA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\lib\netstandard2.0\Microsoft.ML.PCA.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ML.StandardTrainers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\lib\netstandard2.0\Microsoft.ML.StandardTrainers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ML.Transforms, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\lib\netstandard2.0\Microsoft.ML.Transforms.dll</HintPath>
|
||||
<Reference Include="Microsoft.Web.WebView2.WinForms, Version=1.0.3800.47, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.3800.47\lib\net462\Microsoft.Web.WebView2.WinForms.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="RestSharp, Version=112.1.1.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\RestSharp.112.1.1-alpha.0.4\lib\net48\RestSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="System.Xaml" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.6.1\lib\net462\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.CodeDom, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.CodeDom.10.0.0-preview.4.25258.110\lib\net462\System.CodeDom.dll</HintPath>
|
||||
<HintPath>..\packages\System.CodeDom.10.0.0-rc.1.25451.107\lib\net462\System.CodeDom.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Collections.Immutable, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.10.0.0-preview.4.25258.110\lib\net462\System.Collections.Immutable.dll</HintPath>
|
||||
<HintPath>..\packages\System.Collections.Immutable.10.0.0-rc.1.25451.107\lib\net462\System.Collections.Immutable.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.IO.Pipelines, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Pipelines.10.0.0-preview.2.25163.2\lib\net462\System.IO.Pipelines.dll</HintPath>
|
||||
<HintPath>..\packages\System.IO.Pipelines.10.0.0-rc.1.25451.107\lib\net462\System.IO.Pipelines.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Memory, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.6.3\lib\net462\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Tensors, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Tensors.10.0.0-preview.4.25258.110\lib\net462\System.Numerics.Tensors.dll</HintPath>
|
||||
<HintPath>..\packages\System.Numerics.Tensors.10.0.0-rc.1.25451.107\lib\net462\System.Numerics.Tensors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.6.1\lib\net462\System.Numerics.Vectors.dll</HintPath>
|
||||
@@ -134,13 +105,13 @@
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.1.2\lib\net462\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Encodings.Web, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Encodings.Web.10.0.0-preview.2.25163.2\lib\net462\System.Text.Encodings.Web.dll</HintPath>
|
||||
<HintPath>..\packages\System.Text.Encodings.Web.10.0.0-rc.1.25451.107\lib\net462\System.Text.Encodings.Web.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Json.10.0.0-preview.2.25163.2\lib\net462\System.Text.Json.dll</HintPath>
|
||||
<HintPath>..\packages\System.Text.Json.10.0.0-rc.1.25451.107\lib\net462\System.Text.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Channels, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Channels.10.0.0-preview.4.25258.110\lib\net462\System.Threading.Channels.dll</HintPath>
|
||||
<HintPath>..\packages\System.Threading.Channels.10.0.0-rc.1.25451.107\lib\net462\System.Threading.Channels.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.4.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.6.3\lib\net462\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
@@ -150,13 +121,28 @@
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="VirtualFootball\VirtualMatch.cs" />
|
||||
<Page Include="MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CsvHelperStubs.cs" />
|
||||
<Compile Include="MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Football\Database\BetType.cs" />
|
||||
<Compile Include="Football\Database\Bookmaker.cs" />
|
||||
<Compile Include="Football\Database\APIResponse.cs" />
|
||||
@@ -178,12 +164,10 @@
|
||||
<Compile Include="Football\Database\Prediction.cs" />
|
||||
<Compile Include="Football\Database\Score.cs" />
|
||||
<Compile Include="Football\Database\Team.cs" />
|
||||
<Compile Include="HorseRacing\API\RacingApiClient.cs" />
|
||||
<Compile Include="HorseRacing\Main.cs" />
|
||||
<Compile Include="Horses\Calculator.cs" />
|
||||
<Compile Include="Horses\Files\Maps\Punters.cs" />
|
||||
<Compile Include="Horses\ML\HorseRacePrediction.cs" />
|
||||
<Compile Include="Horses\ML\MachineLearningService.cs" />
|
||||
<Compile Include="Horses\ML\ModelInput.cs" />
|
||||
<Compile Include="Horses\ML\ModelOutput.cs" />
|
||||
<Compile Include="Manager\API.cs" />
|
||||
<Compile Include="Manager\FileReader.cs" />
|
||||
<Compile Include="Manager\Database.cs" />
|
||||
@@ -191,17 +175,7 @@
|
||||
<Compile Include="Horses\FileReader.cs" />
|
||||
<Compile Include="Horses\Database.cs" />
|
||||
<Compile Include="Horses\Files\Punters.cs" />
|
||||
<Compile Include="Main.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Main.Designer.cs">
|
||||
<DependentUpon>Main.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<EmbeddedResource Include="Main.resx">
|
||||
<DependentUpon>Main.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
@@ -211,7 +185,6 @@
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<None Include="Dati\Result.csv" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
@@ -227,23 +200,20 @@
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Query\ScanFavoriteHorseWeights.sql" />
|
||||
<Content Include="Query\PredictionScanResults.sql" />
|
||||
<Content Include="Query\GetFavoriteHorses.sql" />
|
||||
<Content Include="Query\GetValidHorses.sql" />
|
||||
<Content Include="Query\Races.sql" />
|
||||
<Folder Include="Themes\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\System.ValueTuple.4.6.1\build\net471\System.ValueTuple.targets" Condition="Exists('..\packages\System.ValueTuple.4.6.1\build\net471\System.ValueTuple.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>Questo progetto fa riferimento a uno o più pacchetti NuGet che non sono presenti in questo computer. Usare lo strumento di ripristino dei pacchetti NuGet per scaricarli. Per altre informazioni, vedere http://go.microsoft.com/fwlink/?LinkID=322105. Il file mancante è {0}.</ErrorText>
|
||||
<ErrorText>Questo progetto fa riferimento a uno o pi<EFBFBD> pacchetti NuGet che non sono presenti in questo computer. Usare lo strumento di ripristino dei pacchetti NuGet per scaricarli. Per altre informazioni, vedere http://go.microsoft.com/fwlink/?LinkID=322105. Il file mancante <EFBFBD> {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\System.ValueTuple.4.6.1\build\net471\System.ValueTuple.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.ValueTuple.4.6.1\build\net471\System.ValueTuple.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.ML.CpuMath.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.CpuMath.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.ML.CpuMath.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.CpuMath.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.ML.FastTree.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.FastTree.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.ML.FastTree.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.FastTree.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.ML.CpuMath.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.CpuMath.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.ML.CpuMath.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.CpuMath.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.ML.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.ML.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.ML.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.ML.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.ML.FastTree.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.FastTree.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.ML.FastTree.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.FastTree.props'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.targets" Condition="Exists('..\packages\Microsoft.ML.5.0.0-preview.1.25127.4\build\netstandard2.0\Microsoft.ML.targets')" />
|
||||
<Import Project="..\packages\Microsoft.Web.WebView2.1.0.3800.47\build\Microsoft.Web.WebView2.targets" Condition="Exists('..\packages\Microsoft.Web.WebView2.1.0.3800.47\build\Microsoft.Web.WebView2.targets')" />
|
||||
<Import Project="..\packages\Microsoft.ML.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.targets" Condition="Exists('..\packages\Microsoft.ML.5.0.0-preview.25503.2\build\netstandard2.0\Microsoft.ML.targets')" />
|
||||
</Project>
|
||||
115
HorseRacingPredictor/HorseRacingPredictor/CsvHelperStubs.cs
Normal file
115
HorseRacingPredictor/HorseRacingPredictor/CsvHelperStubs.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Globalization;
|
||||
|
||||
// Minimal compatibility stubs for CsvHelper types used in the project.
|
||||
// These are light-weight placeholders so the project can compile when the CsvHelper NuGet
|
||||
// package is not restored. They intentionally provide only the members the project expects.
|
||||
|
||||
namespace CsvHelper.Configuration.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
|
||||
public sealed class NameAttribute : Attribute
|
||||
{
|
||||
public string[] Names { get; }
|
||||
public NameAttribute(params string[] names) => Names = names ?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
|
||||
public sealed class TypeConverterAttribute : Attribute
|
||||
{
|
||||
public Type ConverterType { get; }
|
||||
public TypeConverterAttribute(Type converterType) => ConverterType = converterType;
|
||||
}
|
||||
}
|
||||
|
||||
namespace CsvHelper.TypeConversion
|
||||
{
|
||||
public class DefaultTypeConverter
|
||||
{
|
||||
// Signature matches CsvHelper's DefaultTypeConverter override used in the project
|
||||
public virtual object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData) => (object)text;
|
||||
}
|
||||
|
||||
public class TypeConverterCache
|
||||
{
|
||||
private readonly Dictionary<Type, object> _converters = new Dictionary<Type, object>();
|
||||
public void AddConverter<T>(DefaultTypeConverter converter) => _converters[typeof(T)] = converter;
|
||||
}
|
||||
|
||||
// Minimal placeholders referenced in code
|
||||
public interface IReaderRow { }
|
||||
public class MemberMapData { }
|
||||
}
|
||||
|
||||
namespace CsvHelper.Configuration
|
||||
{
|
||||
public enum TrimOptions { None, Trim }
|
||||
|
||||
public class CsvConfiguration
|
||||
{
|
||||
public CsvConfiguration(CultureInfo culture) { Culture = culture; }
|
||||
public CultureInfo Culture { get; }
|
||||
public bool HasHeaderRecord { get; set; }
|
||||
public Func<PrepareHeaderForMatchArgs, string> PrepareHeaderForMatch { get; set; }
|
||||
public object HeaderValidated { get; set; }
|
||||
public Action<object> MissingFieldFound { get; set; }
|
||||
public Action<object> BadDataFound { get; set; }
|
||||
public TrimOptions TrimOptions { get; set; }
|
||||
public string Delimiter { get; set; }
|
||||
}
|
||||
|
||||
// Basic ClassMap and mapping helper used by the project's mapping files
|
||||
public class ClassMap<T>
|
||||
{
|
||||
public MemberMap Map(Func<T, object> func) => new MemberMap();
|
||||
}
|
||||
|
||||
public class MemberMap
|
||||
{
|
||||
public MemberMap Name(params string[] names) { return this; }
|
||||
}
|
||||
|
||||
// Minimal args used by PrepareHeaderForMatch delegate in code above
|
||||
public class PrepareHeaderForMatchArgs
|
||||
{
|
||||
public string Header { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
namespace CsvHelper
|
||||
{
|
||||
using CsvHelper.Configuration;
|
||||
using CsvHelper.TypeConversion;
|
||||
|
||||
public class CsvReader : IDisposable
|
||||
{
|
||||
private readonly TextReader _reader;
|
||||
public CsvReader(TextReader reader, CsvConfiguration config)
|
||||
{
|
||||
_reader = reader;
|
||||
Configuration = config;
|
||||
Context = new ReaderContext();
|
||||
}
|
||||
|
||||
public CsvConfiguration Configuration { get; }
|
||||
public ReaderContext Context { get; }
|
||||
|
||||
public void Dispose() { /* nothing to dispose in stub */ }
|
||||
|
||||
public bool Read() => false;
|
||||
public void ReadHeader() { }
|
||||
public string[] HeaderRecord => Array.Empty<string>();
|
||||
public string GetField(int index) => null;
|
||||
|
||||
public IEnumerable<T> GetRecords<T>() { return Enumerable.Empty<T>(); }
|
||||
|
||||
public class ReaderContext
|
||||
{
|
||||
public TypeConverterCache TypeConverterCache { get; } = new TypeConverterCache();
|
||||
public void RegisterClassMap<TMap>() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
175783
HorseRacingPredictor/HorseRacingPredictor/Docs/Quote.txt
Normal file
175783
HorseRacingPredictor/HorseRacingPredictor/Docs/Quote.txt
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
583078
HorseRacingPredictor/HorseRacingPredictor/Docs/www.bet365.it.har
Normal file
583078
HorseRacingPredictor/HorseRacingPredictor/Docs/www.bet365.it.har
Normal file
File diff suppressed because one or more lines are too long
@@ -1,20 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class BetType : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public void Upsert(SqlConnection connection, JsonNode betType)
|
||||
public void Upsert(SqlConnection connection, JToken betType)
|
||||
{
|
||||
try
|
||||
{
|
||||
var id = betType["id"]?.GetValue<int>();
|
||||
var id = betType["id"]?.Value<int>();
|
||||
if (id == null) return; // Salta il record se l'id è null
|
||||
|
||||
var query = @"
|
||||
@@ -29,7 +25,7 @@ namespace HorseRacingPredictor.Football.Database
|
||||
using (var command = new SqlCommand(query, connection))
|
||||
{
|
||||
command.Parameters.AddWithValue("@bet_type_id", id);
|
||||
command.Parameters.AddWithValue("@name", betType["name"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@name", betType["name"]?.Value<string>() ?? "");
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class Bookmaker : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public void Upsert(SqlConnection connection, JsonNode bookmaker)
|
||||
public void Upsert(SqlConnection connection, JToken bookmaker)
|
||||
{
|
||||
try
|
||||
{
|
||||
var id = bookmaker["id"]?.GetValue<int>();
|
||||
var id = bookmaker["id"]?.Value<int>();
|
||||
if (id == null) return; // Salta il record se l'id è null
|
||||
|
||||
var query = @"
|
||||
@@ -29,7 +25,7 @@ namespace HorseRacingPredictor.Football.Database
|
||||
using (var command = new SqlCommand(query, connection))
|
||||
{
|
||||
command.Parameters.AddWithValue("@bookmaker_id", id);
|
||||
command.Parameters.AddWithValue("@name", bookmaker["name"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@name", bookmaker["name"]?.Value<string>() ?? "");
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class Comparison : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public void Upsert(SqlConnection connection, int predictionId, JsonNode comparison)
|
||||
public void Upsert(SqlConnection connection, int predictionId, JToken comparison)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -56,20 +52,20 @@ namespace HorseRacingPredictor.Football.Database
|
||||
command.Parameters.AddWithValue("@prediction_id", predictionId);
|
||||
|
||||
// Aggiungi tutti i parametri del confronto
|
||||
command.Parameters.AddWithValue("@form_home", comparison["form"]?["home"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@form_away", comparison["form"]?["away"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@att_home", comparison["att"]?["home"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@att_away", comparison["att"]?["away"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@def_home", comparison["def"]?["home"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@def_away", comparison["def"]?["away"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@poisson_home", comparison["poisson_distribution"]?["home"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@poisson_away", comparison["poisson_distribution"]?["away"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@h2h_home", comparison["h2h"]?["home"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@h2h_away", comparison["h2h"]?["away"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@goals_home", comparison["goals"]?["home"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@goals_away", comparison["goals"]?["away"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@total_home", comparison["total"]?["home"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@total_away", comparison["total"]?["away"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@form_home", comparison["form"]?["home"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@form_away", comparison["form"]?["away"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@att_home", comparison["att"]?["home"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@att_away", comparison["att"]?["away"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@def_home", comparison["def"]?["home"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@def_away", comparison["def"]?["away"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@poisson_home", comparison["poisson_distribution"]?["home"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@poisson_away", comparison["poisson_distribution"]?["away"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@h2h_home", comparison["h2h"]?["home"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@h2h_away", comparison["h2h"]?["away"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@goals_home", comparison["goals"]?["home"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@goals_away", comparison["goals"]?["away"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@total_home", comparison["total"]?["home"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@total_away", comparison["total"]?["away"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Text.Json.Nodes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class Fixture : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public void Upsert(SqlConnection connection, SqlTransaction transaction, JsonNode fixture)
|
||||
public void Upsert(SqlConnection connection, SqlTransaction transaction, JToken fixture)
|
||||
{
|
||||
try
|
||||
{
|
||||
var id = fixture["id"]?.GetValue<int>();
|
||||
var id = fixture["id"]?.Value<int>();
|
||||
if (id == null) return; // Salta il record se l'id è null
|
||||
|
||||
var query = @"
|
||||
@@ -63,20 +63,20 @@ namespace HorseRacingPredictor.Football.Database
|
||||
|
||||
// Parametri principali
|
||||
command.Parameters.AddWithValue("@fixture_id", id);
|
||||
command.Parameters.AddWithValue("@timezone", fixture["timezone"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@date", fixture["date"]?.GetValue<DateTime>() ?? DateTime.MinValue);
|
||||
command.Parameters.AddWithValue("@timestamp", fixture["timestamp"]?.GetValue<long>() ?? 0L);
|
||||
command.Parameters.AddWithValue("@referee", fixture["referee"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@timezone", fixture["timezone"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@date", fixture["date"]?.Value<DateTime>() ?? DateTime.MinValue);
|
||||
command.Parameters.AddWithValue("@timestamp", fixture["timestamp"]?.Value<long>() ?? 0L);
|
||||
command.Parameters.AddWithValue("@referee", fixture["referee"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
|
||||
// Parametri venue
|
||||
int? venueId = venue?["id"]?.GetValue<int?>();
|
||||
int? venueId = venue?["id"]?.Value<int?>();
|
||||
command.Parameters.AddWithValue("@venue_id", venueId.HasValue ? (object)venueId.Value : DBNull.Value);
|
||||
|
||||
// Parametri status
|
||||
command.Parameters.AddWithValue("@status_long", status?["long"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@status_short", status?["short"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@status_long", status?["long"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@status_short", status?["short"]?.Value<string>() ?? "");
|
||||
|
||||
int? elapsed = status?["elapsed"]?.GetValue<int?>();
|
||||
int? elapsed = status?["elapsed"]?.Value<int?>();
|
||||
int? extra = null; // Assumo che l'API restituisca questo valore, altrimenti va gestito come gli altri
|
||||
|
||||
command.Parameters.AddWithValue("@status_elapsed", elapsed.HasValue ? (object)elapsed.Value : DBNull.Value);
|
||||
@@ -101,11 +101,11 @@ namespace HorseRacingPredictor.Football.Database
|
||||
/// <summary>
|
||||
/// Metodo di supporto per inserire/aggiornare le informazioni sulla venue
|
||||
/// </summary>
|
||||
private void UpsertVenue(SqlConnection connection, SqlTransaction transaction, JsonNode venue)
|
||||
private void UpsertVenue(SqlConnection connection, SqlTransaction transaction, JToken venue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var id = venue["id"]?.GetValue<int>();
|
||||
var id = venue["id"]?.Value<int>();
|
||||
if (id == null) return;
|
||||
|
||||
var query = @"
|
||||
@@ -121,8 +121,8 @@ namespace HorseRacingPredictor.Football.Database
|
||||
using (var command = new SqlCommand(query, connection, transaction))
|
||||
{
|
||||
command.Parameters.AddWithValue("@venue_id", id);
|
||||
command.Parameters.AddWithValue("@name", venue["name"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@city", venue["city"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@name", venue["name"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@city", venue["city"]?.Value<string>() ?? "");
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
@@ -153,6 +153,7 @@ namespace HorseRacingPredictor.Football.Database
|
||||
l.country AS Paese,
|
||||
l.name AS Campionato,
|
||||
f.date AS [Data / Ora],
|
||||
f.timestamp AS unix_ts,
|
||||
f.status AS Stato,
|
||||
th.name AS Casa,
|
||||
ta.name AS Trasferta,
|
||||
|
||||
@@ -3,20 +3,20 @@ using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Nodes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class FixtureLeague : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public void Upsert(SqlConnection connection, SqlTransaction transaction, int fixtureId, int leagueId, JsonNode leagueData)
|
||||
public void Upsert(SqlConnection connection, SqlTransaction transaction, int fixtureId, int leagueId, JToken leagueData)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Estrai i valori prima della query per utilizzarli nel log
|
||||
string round = leagueData["round"]?.GetValue<string>() ?? "";
|
||||
bool? standings = leagueData["standings"]?.GetValue<bool?>();
|
||||
string round = leagueData["round"]?.Value<string>() ?? "";
|
||||
bool? standings = leagueData["standings"]?.Value<bool?>();
|
||||
string standingsValue = standings.HasValue ? standings.Value.ToString() : "NULL";
|
||||
|
||||
// Log dell'operazione prima di tentare l'upsert
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Text.Json.Nodes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class Goals : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public void Upsert(SqlConnection connection, JsonNode goals, int fixtureId)
|
||||
public void Upsert(SqlConnection connection, JToken goals, int fixtureId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -27,8 +27,8 @@ namespace HorseRacingPredictor.Football.Database
|
||||
END";
|
||||
using (var command = new SqlCommand(query, connection))
|
||||
{
|
||||
command.Parameters.AddWithValue("@home", goals["home"]?.GetValue<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@away", goals["away"]?.GetValue<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@home", goals["home"]?.Value<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@away", goals["away"]?.Value<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@fixture_id", fixtureId);
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Text.Json.Nodes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class League : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public void Upsert(SqlConnection connection, JsonNode league)
|
||||
public void Upsert(SqlConnection connection, JToken league)
|
||||
{
|
||||
try
|
||||
{
|
||||
var id = league["id"]?.GetValue<int>();
|
||||
var id = league["id"]?.Value<int>();
|
||||
if (id == null) return; // Salta il record se l'id è null
|
||||
|
||||
var query = @"
|
||||
@@ -25,11 +25,11 @@ namespace HorseRacingPredictor.Football.Database
|
||||
using (var command = new SqlCommand(query, connection))
|
||||
{
|
||||
command.Parameters.AddWithValue("@league_id", id);
|
||||
command.Parameters.AddWithValue("@name", league["name"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@country", league["country"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@logo", league["logo"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@flag", league["flag"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@season", league["season"]?.GetValue<int>() ?? 0);
|
||||
command.Parameters.AddWithValue("@name", league["name"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@country", league["country"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@logo", league["logo"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@flag", league["flag"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@season", league["season"]?.Value<int>() ?? 0);
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
@@ -39,11 +39,11 @@ namespace HorseRacingPredictor.Football.Database
|
||||
}
|
||||
}
|
||||
|
||||
public void Upsert(SqlConnection connection, SqlTransaction transaction, JsonNode league)
|
||||
public void Upsert(SqlConnection connection, SqlTransaction transaction, JToken league)
|
||||
{
|
||||
try
|
||||
{
|
||||
var id = league["id"]?.GetValue<int>();
|
||||
var id = league["id"]?.Value<int>();
|
||||
if (id == null) return; // Salta il record se l'id è null
|
||||
|
||||
var query = @"
|
||||
@@ -58,11 +58,11 @@ namespace HorseRacingPredictor.Football.Database
|
||||
using (var command = new SqlCommand(query, connection, transaction))
|
||||
{
|
||||
command.Parameters.AddWithValue("@league_id", id);
|
||||
command.Parameters.AddWithValue("@name", league["name"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@country", league["country"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@logo", league["logo"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@flag", league["flag"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@season", league["season"]?.GetValue<int>() ?? 0);
|
||||
command.Parameters.AddWithValue("@name", league["name"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@country", league["country"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@logo", league["logo"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@flag", league["flag"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@season", league["season"]?.Value<int>() ?? 0);
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Text.Json.Nodes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class LeagueStats : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public int Insert(SqlConnection connection, int? teamId, int? predictionId, bool isHome, JsonNode stats)
|
||||
public int Insert(SqlConnection connection, int? teamId, int? predictionId, bool isHome, JToken stats)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -35,27 +35,27 @@ namespace HorseRacingPredictor.Football.Database
|
||||
command.Parameters.AddWithValue("@team_id", teamId.HasValue ? (object)teamId.Value : DBNull.Value);
|
||||
command.Parameters.AddWithValue("@prediction_id", predictionId.HasValue ? (object)predictionId.Value : DBNull.Value);
|
||||
command.Parameters.AddWithValue("@is_home", isHome);
|
||||
command.Parameters.AddWithValue("@form", stats["form"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@form", stats["form"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
|
||||
var fixtures = stats["fixtures"];
|
||||
command.Parameters.AddWithValue("@fixtures_played_home", fixtures?["played"]?["home"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@fixtures_played_away", fixtures?["played"]?["away"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@fixtures_played_total", fixtures?["played"]?["total"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@fixtures_played_home", fixtures?["played"]?["home"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@fixtures_played_away", fixtures?["played"]?["away"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@fixtures_played_total", fixtures?["played"]?["total"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
|
||||
var wins = stats["fixtures"]?["wins"];
|
||||
command.Parameters.AddWithValue("@wins_home", wins?["home"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@wins_away", wins?["away"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@wins_total", wins?["total"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@wins_home", wins?["home"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@wins_away", wins?["away"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@wins_total", wins?["total"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
|
||||
var draws = stats["fixtures"]?["draws"];
|
||||
command.Parameters.AddWithValue("@draws_home", draws?["home"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@draws_away", draws?["away"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@draws_total", draws?["total"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@draws_home", draws?["home"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@draws_away", draws?["away"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@draws_total", draws?["total"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
|
||||
var loses = stats["fixtures"]?["loses"];
|
||||
command.Parameters.AddWithValue("@loses_home", loses?["home"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@loses_away", loses?["away"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@loses_total", loses?["total"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@loses_home", loses?["home"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@loses_away", loses?["away"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@loses_total", loses?["total"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class Odds : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public void Upsert(SqlConnection connection, JsonNode bookmakers, int fixtureId)
|
||||
public void Upsert(SqlConnection connection, JToken bookmakers, int fixtureId)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Aggiungiamo log per tracciare la struttura dei dati
|
||||
LogError($"Inizio elaborazione quote per fixture {fixtureId} con {bookmakers?.AsArray().Count ?? 0} bookmakers", null);
|
||||
LogError($"Inizio elaborazione quote per fixture {fixtureId} con {bookmakers?.Children().Count() ?? 0} bookmakers", null);
|
||||
|
||||
// Per ogni bookmaker
|
||||
foreach (var bookmaker in bookmakers.AsArray())
|
||||
foreach (var bookmaker in bookmakers.Children())
|
||||
{
|
||||
int bookmakerId = bookmaker["id"].GetValue<int>();
|
||||
int bookmakerId = bookmaker["id"].Value<int>();
|
||||
var bets = bookmaker["bets"];
|
||||
|
||||
// Cerchiamo le quote di tipo Match Winner (1X2)
|
||||
foreach (var bet in bets.AsArray())
|
||||
foreach (var bet in bets.Children())
|
||||
{
|
||||
// Gestiamo in modo più sicuro il recupero di valori dal JSON
|
||||
string betName = GetStringValueSafe(bet, "name");
|
||||
@@ -35,7 +36,7 @@ namespace HorseRacingPredictor.Football.Database
|
||||
if (betTypeId == 0) continue;
|
||||
|
||||
// Estrai e salva le quote
|
||||
foreach (var value in bet["values"].AsArray())
|
||||
foreach (var value in bet["values"].Children())
|
||||
{
|
||||
// Gestiamo in modo più sicuro il recupero di valori dal JSON
|
||||
string valueType = GetStringValueSafe(value, "value");
|
||||
@@ -128,9 +129,9 @@ namespace HorseRacingPredictor.Football.Database
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene un valore stringa da un JsonNode in modo sicuro
|
||||
/// Ottiene un valore stringa da un JToken in modo sicuro
|
||||
/// </summary>
|
||||
private string GetStringValueSafe(JsonNode node, string propertyName)
|
||||
private string GetStringValueSafe(JToken node, string propertyName)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -140,10 +141,10 @@ namespace HorseRacingPredictor.Football.Database
|
||||
var value = node[propertyName];
|
||||
|
||||
// Gestiamo diversi tipi di nodi
|
||||
if (value.GetValueKind() == System.Text.Json.JsonValueKind.String)
|
||||
return value.GetValue<string>();
|
||||
else if (value.GetValueKind() == System.Text.Json.JsonValueKind.Number)
|
||||
return value.GetValue<decimal>().ToString();
|
||||
if (value.Type == JTokenType.String)
|
||||
return value.Value<string>();
|
||||
else if (value.Type == JTokenType.Float || value.Type == JTokenType.Integer)
|
||||
return value.Value<decimal>().ToString();
|
||||
else
|
||||
return value.ToString();
|
||||
}
|
||||
@@ -155,9 +156,9 @@ namespace HorseRacingPredictor.Football.Database
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene un valore decimale da un JsonNode in modo sicuro
|
||||
/// Ottiene un valore decimale da un JToken in modo sicuro
|
||||
/// </summary>
|
||||
private decimal GetDecimalValueSafe(JsonNode node, string propertyName)
|
||||
private decimal GetDecimalValueSafe(JToken node, string propertyName)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -167,15 +168,15 @@ namespace HorseRacingPredictor.Football.Database
|
||||
var value = node[propertyName];
|
||||
|
||||
// Gestiamo diversi tipi di nodi
|
||||
if (value.GetValueKind() == System.Text.Json.JsonValueKind.Number)
|
||||
if (value.Type == JTokenType.Float || value.Type == JTokenType.Integer)
|
||||
{
|
||||
// Assicuriamoci che il valore sia esattamente quello originale
|
||||
return value.GetValue<decimal>();
|
||||
return value.Value<decimal>();
|
||||
}
|
||||
else if (value.GetValueKind() == System.Text.Json.JsonValueKind.String)
|
||||
else if (value.Type == JTokenType.String)
|
||||
{
|
||||
// Utilizziamo InvariantCulture per garantire una corretta interpretazione dei decimali
|
||||
if (decimal.TryParse(value.GetValue<string>(),
|
||||
if (decimal.TryParse(value.Value<string>(),
|
||||
System.Globalization.NumberStyles.Any,
|
||||
System.Globalization.CultureInfo.InvariantCulture,
|
||||
out decimal result))
|
||||
@@ -185,7 +186,7 @@ namespace HorseRacingPredictor.Football.Database
|
||||
}
|
||||
|
||||
// Aggiungiamo un log più dettagliato per aiutare il debug
|
||||
LogError($"Impossibile convertire '{value}' (tipo: {value.GetValueKind()}) in decimal per proprietà '{propertyName}'", null);
|
||||
LogError($"Impossibile convertire '{value}' (tipo: {value.Type}) in decimal per proprietà '{propertyName}'", null);
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Text.Json.Nodes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class Prediction : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public void Upsert(SqlConnection connection, JsonNode predictions, int fixtureId)
|
||||
public void Upsert(SqlConnection connection, JToken predictions, int fixtureId)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Estrazione dei dati dalla risposta JSON
|
||||
string advice = predictions["advice"]?.GetValue<string>();
|
||||
string advice = predictions["advice"]?.Value<string>();
|
||||
if (string.IsNullOrEmpty(advice)) return; // Nessuna previsione se non c'è consiglio
|
||||
|
||||
// Estrazione degli altri valori, con gestione null
|
||||
int? winnerId = predictions["winner"]?["id"]?.GetValue<int?>();
|
||||
string winnerName = predictions["winner"]?["name"]?.GetValue<string>();
|
||||
string winnerComment = predictions["winner"]?["comment"]?.GetValue<string>();
|
||||
bool? winOrDraw = predictions["win_or_draw"]?.GetValue<bool?>();
|
||||
string underOver = predictions["under_over"]?.GetValue<string>();
|
||||
string goalsHome = predictions["goals"]?["home"]?.GetValue<string>();
|
||||
string goalsAway = predictions["goals"]?["away"]?.GetValue<string>();
|
||||
string percentHome = predictions["percent"]?["home"]?.GetValue<string>();
|
||||
string percentDraw = predictions["percent"]?["draw"]?.GetValue<string>();
|
||||
string percentAway = predictions["percent"]?["away"]?.GetValue<string>();
|
||||
int? winnerId = predictions["winner"]?["id"]?.Value<int?>();
|
||||
string winnerName = predictions["winner"]?["name"]?.Value<string>();
|
||||
string winnerComment = predictions["winner"]?["comment"]?.Value<string>();
|
||||
bool? winOrDraw = predictions["win_or_draw"]?.Value<bool?>();
|
||||
string underOver = predictions["under_over"]?.Value<string>();
|
||||
string goalsHome = predictions["goals"]?["home"]?.Value<string>();
|
||||
string goalsAway = predictions["goals"]?["away"]?.Value<string>();
|
||||
string percentHome = predictions["percent"]?["home"]?.Value<string>();
|
||||
string percentDraw = predictions["percent"]?["draw"]?.Value<string>();
|
||||
string percentAway = predictions["percent"]?["away"]?.Value<string>();
|
||||
|
||||
// Query per l'upsert con tutti i campi disponibili
|
||||
var query = @"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Text.Json.Nodes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class Score : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public void Upsert(SqlConnection connection, JsonNode score, int fixtureId)
|
||||
public void Upsert(SqlConnection connection, JToken score, int fixtureId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -26,14 +26,14 @@ namespace HorseRacingPredictor.Football.Database
|
||||
END";
|
||||
using (var command = new SqlCommand(query, connection))
|
||||
{
|
||||
command.Parameters.AddWithValue("@home_halftime", score["halftime"]["home"]?.GetValue<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@away_halftime", score["halftime"]["away"]?.GetValue<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@home_fulltime", score["fulltime"]["home"]?.GetValue<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@away_fulltime", score["fulltime"]["away"]?.GetValue<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@home_extratime", score["extratime"]["home"]?.GetValue<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@away_extratime", score["extratime"]["away"]?.GetValue<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@home_penalty", score["penalty"]["home"]?.GetValue<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@away_penalty", score["penalty"]["away"]?.GetValue<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@home_halftime", score["halftime"]?["home"]?.Value<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@away_halftime", score["halftime"]?["away"]?.Value<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@home_fulltime", score["fulltime"]?["home"]?.Value<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@away_fulltime", score["fulltime"]?["away"]?.Value<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@home_extratime", score["extratime"]?["home"]?.Value<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@away_extratime", score["extratime"]?["away"]?.Value<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@home_penalty", score["penalty"]?["home"]?.Value<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@away_penalty", score["penalty"]?["away"]?.Value<int?>() ?? 0);
|
||||
command.Parameters.AddWithValue("@fixture_id", fixtureId);
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Text.Json.Nodes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class Team : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public void UpsertTeams(SqlConnection connection, SqlTransaction transaction, JsonNode teams, int fixtureId)
|
||||
public void UpsertTeams(SqlConnection connection, SqlTransaction transaction, JToken teams, int fixtureId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var homeTeamId = teams["home"]["id"]?.GetValue<int>();
|
||||
var awayTeamId = teams["away"]["id"]?.GetValue<int>();
|
||||
var homeTeamId = teams["home"]["id"]?.Value<int>();
|
||||
var awayTeamId = teams["away"]["id"]?.Value<int>();
|
||||
if (homeTeamId == null || awayTeamId == null) return; // Salta il record se uno degli id è null
|
||||
|
||||
var queryTeam = @"
|
||||
@@ -31,14 +31,14 @@ namespace HorseRacingPredictor.Football.Database
|
||||
|
||||
// Upsert home team
|
||||
command.Parameters.AddWithValue("@team_id", homeTeamId);
|
||||
command.Parameters.AddWithValue("@name", homeTeam["name"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@logo", homeTeam["logo"]?.GetValue<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@name", homeTeam["name"]?.Value<string>() ?? "");
|
||||
command.Parameters.AddWithValue("@logo", homeTeam["logo"]?.Value<string>() ?? "");
|
||||
command.ExecuteNonQuery();
|
||||
|
||||
// Upsert away team
|
||||
command.Parameters["@team_id"].Value = awayTeamId;
|
||||
command.Parameters["@name"].Value = awayTeam["name"]?.GetValue<string>() ?? "";
|
||||
command.Parameters["@logo"].Value = awayTeam["logo"]?.GetValue<string>() ?? "";
|
||||
command.Parameters["@name"].Value = awayTeam["name"]?.Value<string>() ?? "";
|
||||
command.Parameters["@logo"].Value = awayTeam["logo"]?.Value<string>() ?? "";
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HorseRacingPredictor.Football.Database
|
||||
{
|
||||
internal class TeamStats : HorseRacingPredictor.Football.Manager.Database
|
||||
{
|
||||
public int Insert(SqlConnection connection, int? teamId, int? predictionId, bool isHome, JsonNode stats)
|
||||
public int Insert(SqlConnection connection, int? teamId, int? predictionId, bool isHome, JToken stats)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -35,18 +31,18 @@ namespace HorseRacingPredictor.Football.Database
|
||||
command.Parameters.AddWithValue("@team_id", teamId.HasValue ? (object)teamId.Value : DBNull.Value);
|
||||
command.Parameters.AddWithValue("@prediction_id", predictionId.HasValue ? (object)predictionId.Value : DBNull.Value);
|
||||
command.Parameters.AddWithValue("@is_home", isHome);
|
||||
command.Parameters.AddWithValue("@played", stats["played"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@form", stats["form"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@att", stats["att"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@def", stats["def"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@played", stats["played"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@form", stats["form"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@att", stats["att"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@def", stats["def"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
|
||||
var goalsFor = stats["goals"]?["for"];
|
||||
command.Parameters.AddWithValue("@goals_for_total", goalsFor?["total"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@goals_for_average", goalsFor?["average"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@goals_for_total", goalsFor?["total"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@goals_for_average", goalsFor?["average"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
|
||||
var goalsAgainst = stats["goals"]?["against"];
|
||||
command.Parameters.AddWithValue("@goals_against_total", goalsAgainst?["total"]?.GetValue<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@goals_against_average", goalsAgainst?["average"]?.GetValue<string>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@goals_against_total", goalsAgainst?["total"]?.Value<int?>() ?? (object)DBNull.Value);
|
||||
command.Parameters.AddWithValue("@goals_against_average", goalsAgainst?["average"]?.Value<string>() ?? (object)DBNull.Value);
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using RestSharp;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Data.SqlClient;
|
||||
|
||||
namespace HorseRacingPredictor.Football
|
||||
@@ -97,6 +98,42 @@ namespace HorseRacingPredictor.Football
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupera solo l'elenco delle partite per la data specificata e le restituisce come DataTable semplice
|
||||
/// </summary>
|
||||
public DataTable GetTodayFixtures(DateTime date, IProgress<int> progressCallback = null, IProgress<string> statusCallback = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
statusCallback?.Report("Scaricamento elenco partite...");
|
||||
progressCallback?.Report(10);
|
||||
|
||||
var fixturesResponse = GetFixtures(date);
|
||||
progressCallback?.Report(40);
|
||||
|
||||
statusCallback?.Report("Elaborazione partite...");
|
||||
var table = CreateFixturesDataTable(fixturesResponse);
|
||||
progressCallback?.Report(50);
|
||||
|
||||
statusCallback?.Report("Scaricamento quote...");
|
||||
var oddsResponses = GetOdds(date);
|
||||
progressCallback?.Report(80);
|
||||
|
||||
statusCallback?.Report("Integrazione quote...");
|
||||
ParseOddsIntoTable(table, oddsResponses);
|
||||
progressCallback?.Report(100);
|
||||
|
||||
statusCallback?.Report($"Trovate {table.Rows.Count} partite con quote");
|
||||
return table;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_database.LogError("recupero partite del giorno", ex);
|
||||
statusCallback?.Report($"Errore: {ex.Message}");
|
||||
return CreateEmptyResultTable();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scarica i dati dalle API e li salva nella tabella di frontiera API_Response
|
||||
/// </summary>
|
||||
@@ -281,7 +318,13 @@ namespace HorseRacingPredictor.Football
|
||||
{
|
||||
try
|
||||
{
|
||||
var jsonObject = JsonNode.Parse(jsonResponse);
|
||||
// Parse JSON using System.Text.Json and convert to Newtonsoft.JToken where needed
|
||||
var jsonNode = JsonNode.Parse(jsonResponse);
|
||||
var jsonObject = JObject.Parse(jsonNode.ToJsonString());
|
||||
|
||||
// Helper to enumerate array-like tokens (compat replacement for JsonNode.AsArray())
|
||||
var responseArray = jsonObject["response"] as JArray;
|
||||
Func<JToken, IEnumerable<JToken>> asArray = t => t is JArray a ? a : (t != null ? t.Children() : Enumerable.Empty<JToken>());
|
||||
|
||||
_database.ExecuteTransactionalQuery("l'elaborazione dei dati calcistici", (connection, transaction) =>
|
||||
{
|
||||
@@ -291,7 +334,7 @@ namespace HorseRacingPredictor.Football
|
||||
((Manager.Database)_database).DisableAllConstraints(connection, transaction);
|
||||
|
||||
// FASE 1: Inserisci le leghe
|
||||
foreach (var responseItem in jsonObject["response"].AsArray())
|
||||
foreach (var responseItem in asArray(jsonObject["response"]))
|
||||
{
|
||||
var league = responseItem["league"];
|
||||
if (league != null && league["id"] != null)
|
||||
@@ -301,11 +344,11 @@ namespace HorseRacingPredictor.Football
|
||||
}
|
||||
|
||||
// FASE 2: Inserisci i bookmakers e i tipi di scommessa
|
||||
foreach (var responseItem in jsonObject["response"].AsArray())
|
||||
foreach (var responseItem in asArray(jsonObject["response"]))
|
||||
{
|
||||
if (responseItem["bookmakers"] != null)
|
||||
{
|
||||
foreach (var bookmaker in responseItem["bookmakers"].AsArray())
|
||||
foreach (var bookmaker in asArray(responseItem["bookmakers"]))
|
||||
{
|
||||
if (bookmaker["id"] != null)
|
||||
{
|
||||
@@ -314,7 +357,7 @@ namespace HorseRacingPredictor.Football
|
||||
// Tipi di scommessa
|
||||
if (bookmaker["bets"] != null)
|
||||
{
|
||||
foreach (var bet in bookmaker["bets"].AsArray())
|
||||
foreach (var bet in asArray(bookmaker["bets"]))
|
||||
{
|
||||
if (bet["id"] != null && bet["name"] != null)
|
||||
{
|
||||
@@ -328,7 +371,7 @@ namespace HorseRacingPredictor.Football
|
||||
}
|
||||
|
||||
// FASE 3: Inserisci le squadre (senza relazione con fixture)
|
||||
foreach (var responseItem in jsonObject["response"].AsArray())
|
||||
foreach (var responseItem in asArray(jsonObject["response"]))
|
||||
{
|
||||
var teams = responseItem["teams"];
|
||||
if (teams != null && teams["home"] != null && teams["away"] != null &&
|
||||
@@ -340,7 +383,7 @@ namespace HorseRacingPredictor.Football
|
||||
}
|
||||
|
||||
// FASE 4: Inserisci i fixture e venue
|
||||
foreach (var responseItem in jsonObject["response"].AsArray())
|
||||
foreach (var responseItem in asArray(jsonObject["response"]))
|
||||
{
|
||||
var fixture = responseItem["fixture"];
|
||||
if (fixture != null && fixture["id"] != null)
|
||||
@@ -350,7 +393,7 @@ namespace HorseRacingPredictor.Football
|
||||
}
|
||||
|
||||
// FASE 5: Inserisci relazioni tra entità e dati dipendenti
|
||||
foreach (var responseItem in jsonObject["response"].AsArray())
|
||||
foreach (var responseItem in asArray(jsonObject["response"]))
|
||||
{
|
||||
int? fixtureId = null;
|
||||
try
|
||||
@@ -358,7 +401,7 @@ namespace HorseRacingPredictor.Football
|
||||
var fixture = responseItem["fixture"];
|
||||
if (fixture != null && fixture["id"] != null)
|
||||
{
|
||||
fixtureId = fixture["id"].GetValue<int>();
|
||||
fixtureId = fixture["id"].Value<int>();
|
||||
|
||||
// Relazioni fixture-team
|
||||
var teams = responseItem["teams"];
|
||||
@@ -372,7 +415,7 @@ namespace HorseRacingPredictor.Football
|
||||
var league = responseItem["league"];
|
||||
if (league != null && league["id"] != null)
|
||||
{
|
||||
int leagueId = league["id"].GetValue<int>();
|
||||
int leagueId = league["id"].Value<int>();
|
||||
_fixtureLeagueRepository.Upsert(connection, transaction, fixtureId.Value, leagueId, league);
|
||||
}
|
||||
|
||||
@@ -399,7 +442,7 @@ namespace HorseRacingPredictor.Football
|
||||
}
|
||||
|
||||
// FASE 6: Inserisci dati che richiedono fixture e teams: quote e previsioni
|
||||
foreach (var responseItem in jsonObject["response"].AsArray())
|
||||
foreach (var responseItem in asArray(jsonObject["response"]))
|
||||
{
|
||||
int? fixtureId = null;
|
||||
try
|
||||
@@ -407,7 +450,7 @@ namespace HorseRacingPredictor.Football
|
||||
var fixture = responseItem["fixture"];
|
||||
if (fixture != null && fixture["id"] != null)
|
||||
{
|
||||
fixtureId = fixture["id"].GetValue<int>();
|
||||
fixtureId = fixture["id"].Value<int>();
|
||||
|
||||
// Quote
|
||||
if (responseItem["bookmakers"] != null)
|
||||
@@ -442,15 +485,15 @@ namespace HorseRacingPredictor.Football
|
||||
}
|
||||
|
||||
// Head-to-head
|
||||
if (predictions["h2h"] != null && predictions["h2h"].AsArray().Any())
|
||||
if (predictions["h2h"] != null && asArray(predictions["h2h"]).Any())
|
||||
{
|
||||
_h2hRepository.DeleteForPrediction(connection, predictionId.Value);
|
||||
|
||||
foreach (var h2hFixture in predictions["h2h"].AsArray())
|
||||
foreach (var h2hFixture in asArray(predictions["h2h"]))
|
||||
{
|
||||
if (h2hFixture["fixture"] != null && h2hFixture["fixture"]["id"] != null)
|
||||
{
|
||||
_h2hRepository.Insert(connection, predictionId.Value, h2hFixture["fixture"]["id"].GetValue<int>());
|
||||
_h2hRepository.Insert(connection, predictionId.Value, h2hFixture["fixture"]["id"].Value<int>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -462,7 +505,7 @@ namespace HorseRacingPredictor.Football
|
||||
// Home team stats
|
||||
if (teams["home"] != null && teams["home"]["id"] != null && predictions["teams"]["home"] != null)
|
||||
{
|
||||
int homeTeamId = teams["home"]["id"].GetValue<int>();
|
||||
int homeTeamId = teams["home"]["id"].Value<int>();
|
||||
|
||||
if (predictions["teams"]["home"]["team"] != null)
|
||||
{
|
||||
@@ -480,7 +523,7 @@ namespace HorseRacingPredictor.Football
|
||||
// Away team stats
|
||||
if (teams["away"] != null && teams["away"]["id"] != null && predictions["teams"]["away"] != null)
|
||||
{
|
||||
int awayTeamId = teams["away"]["id"].GetValue<int>();
|
||||
int awayTeamId = teams["away"]["id"].Value<int>();
|
||||
|
||||
if (predictions["teams"]["away"]["team"] != null)
|
||||
{
|
||||
@@ -563,6 +606,13 @@ namespace HorseRacingPredictor.Football
|
||||
dataTable.Columns.Add("Quota Casa", typeof(string));
|
||||
dataTable.Columns.Add("Quota Pareggio", typeof(string));
|
||||
dataTable.Columns.Add("Quota Trasferta", typeof(string));
|
||||
dataTable.Columns.Add("Over 2.5", typeof(string));
|
||||
dataTable.Columns.Add("Under 2.5", typeof(string));
|
||||
dataTable.Columns.Add("BTTS Sì", typeof(string));
|
||||
dataTable.Columns.Add("BTTS No", typeof(string));
|
||||
dataTable.Columns.Add("Doppia Casa/X", typeof(string));
|
||||
dataTable.Columns.Add("Doppia Casa/Trasf", typeof(string));
|
||||
dataTable.Columns.Add("Doppia X/Trasf", typeof(string));
|
||||
dataTable.Columns.Add("Previsione", typeof(string));
|
||||
|
||||
return dataTable;
|
||||
@@ -596,28 +646,65 @@ namespace HorseRacingPredictor.Football
|
||||
{
|
||||
try
|
||||
{
|
||||
// Verifica che le proprietà essenziali esistano
|
||||
if (!item.TryGetProperty("fixture", out var fixtureEl) ||
|
||||
!item.TryGetProperty("league", out var leagueEl) ||
|
||||
!item.TryGetProperty("teams", out var teamsEl))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var row = dataTable.NewRow();
|
||||
|
||||
// Estrai i dati dalla risposta JSON
|
||||
row["ID"] = item.GetProperty("fixture").GetProperty("id").GetInt32();
|
||||
row["Paese"] = item.GetProperty("league").GetProperty("country").GetString();
|
||||
row["Campionato"] = item.GetProperty("league").GetProperty("name").GetString();
|
||||
row["Data / Ora"] = DateTime.Parse(item.GetProperty("fixture").GetProperty("date").GetString());
|
||||
row["Stato"] = item.GetProperty("fixture").GetProperty("status").GetProperty("long").GetString();
|
||||
row["Casa"] = item.GetProperty("teams").GetProperty("home").GetProperty("name").GetString();
|
||||
row["Trasferta"] = item.GetProperty("teams").GetProperty("away").GetProperty("name").GetString();
|
||||
row["ID"] = fixtureEl.TryGetProperty("id", out var idEl) ? idEl.GetInt32() : 0;
|
||||
row["Paese"] = leagueEl.TryGetProperty("country", out var countryEl) ? countryEl.GetString() ?? "" : "";
|
||||
row["Campionato"] = leagueEl.TryGetProperty("name", out var leagueNameEl) ? leagueNameEl.GetString() ?? "" : "";
|
||||
|
||||
// Per i goals, controlla se sono null
|
||||
var goalsElement = item.GetProperty("goals");
|
||||
row["Goals Casa"] = goalsElement.GetProperty("home").ValueKind == JsonValueKind.Null ?
|
||||
0 : goalsElement.GetProperty("home").GetInt32();
|
||||
row["Goals Trasferta"] = goalsElement.GetProperty("away").ValueKind == JsonValueKind.Null ?
|
||||
0 : goalsElement.GetProperty("away").GetInt32();
|
||||
if (fixtureEl.TryGetProperty("date", out var dateEl) && dateEl.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
DateTime.TryParse(dateEl.GetString(), out var parsedDate);
|
||||
row["Data / Ora"] = parsedDate;
|
||||
}
|
||||
else
|
||||
{
|
||||
row["Data / Ora"] = DBNull.Value;
|
||||
}
|
||||
|
||||
row["Stato"] = fixtureEl.TryGetProperty("status", out var statusEl) &&
|
||||
statusEl.TryGetProperty("long", out var statusLong)
|
||||
? statusLong.GetString() ?? "" : "";
|
||||
|
||||
row["Casa"] = teamsEl.TryGetProperty("home", out var homeEl) &&
|
||||
homeEl.TryGetProperty("name", out var homeNameEl)
|
||||
? homeNameEl.GetString() ?? "" : "";
|
||||
row["Trasferta"] = teamsEl.TryGetProperty("away", out var awayEl) &&
|
||||
awayEl.TryGetProperty("name", out var awayNameEl)
|
||||
? awayNameEl.GetString() ?? "" : "";
|
||||
|
||||
// Goals (possono essere null per partite non iniziate)
|
||||
if (item.TryGetProperty("goals", out var goalsElement))
|
||||
{
|
||||
row["Goals Casa"] = goalsElement.TryGetProperty("home", out var ghEl) && ghEl.ValueKind == JsonValueKind.Number
|
||||
? ghEl.GetInt32() : 0;
|
||||
row["Goals Trasferta"] = goalsElement.TryGetProperty("away", out var gaEl) && gaEl.ValueKind == JsonValueKind.Number
|
||||
? gaEl.GetInt32() : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
row["Goals Casa"] = 0;
|
||||
row["Goals Trasferta"] = 0;
|
||||
}
|
||||
|
||||
// Le colonne delle quote e previsione rimangono temporaneamente vuote
|
||||
row["Quota Casa"] = DBNull.Value;
|
||||
row["Quota Pareggio"] = DBNull.Value;
|
||||
row["Quota Trasferta"] = DBNull.Value;
|
||||
row["Over 2.5"] = DBNull.Value;
|
||||
row["Under 2.5"] = DBNull.Value;
|
||||
row["BTTS Sì"] = DBNull.Value;
|
||||
row["BTTS No"] = DBNull.Value;
|
||||
row["Doppia Casa/X"] = DBNull.Value;
|
||||
row["Doppia Casa/Trasf"] = DBNull.Value;
|
||||
row["Doppia X/Trasf"] = DBNull.Value;
|
||||
row["Previsione"] = DBNull.Value;
|
||||
|
||||
dataTable.Rows.Add(row);
|
||||
@@ -625,14 +712,12 @@ namespace HorseRacingPredictor.Football
|
||||
catch (Exception ex)
|
||||
{
|
||||
_database.LogError($"elaborazione riga partita", ex);
|
||||
// Continua con la prossima partita
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_database.LogError("creazione tabella partite", ex);
|
||||
// Ritorna la tabella vuota in caso di errore
|
||||
}
|
||||
|
||||
return dataTable;
|
||||
@@ -788,6 +873,162 @@ namespace HorseRacingPredictor.Football
|
||||
return table;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Analizza le risposte delle quote dall'API e le inserisce direttamente nella DataTable delle partite.
|
||||
/// Utilizza Bet365 (ID 8) come bookmaker principale; se non presente, usa il primo bookmaker disponibile.
|
||||
/// </summary>
|
||||
private void ParseOddsIntoTable(DataTable fixturesTable, List<RestResponse> oddsResponses)
|
||||
{
|
||||
if (oddsResponses == null || oddsResponses.Count == 0 || fixturesTable == null || fixturesTable.Rows.Count == 0)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var response in oddsResponses)
|
||||
{
|
||||
if (response == null || !response.IsSuccessful || string.IsNullOrEmpty(response.Content))
|
||||
continue;
|
||||
|
||||
var json = JsonDocument.Parse(response.Content).RootElement;
|
||||
if (!json.TryGetProperty("response", out var responseElement))
|
||||
continue;
|
||||
|
||||
foreach (var item in responseElement.EnumerateArray())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!item.TryGetProperty("fixture", out var fixtureEl))
|
||||
continue;
|
||||
|
||||
int fixtureId = fixtureEl.GetProperty("id").GetInt32();
|
||||
|
||||
DataRow[] matchingRows = fixturesTable.Select($"ID = {fixtureId}");
|
||||
if (matchingRows.Length == 0)
|
||||
continue;
|
||||
|
||||
DataRow row = matchingRows[0];
|
||||
|
||||
if (!item.TryGetProperty("bookmakers", out var bookmakersEl))
|
||||
continue;
|
||||
|
||||
// Cerca Bet365 (ID 8), altrimenti usa il primo bookmaker
|
||||
JsonElement selectedBookmaker = default;
|
||||
bool found = false;
|
||||
|
||||
foreach (var bm in bookmakersEl.EnumerateArray())
|
||||
{
|
||||
if (bm.TryGetProperty("id", out var bmId) && bmId.GetInt32() == 8)
|
||||
{
|
||||
selectedBookmaker = bm;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
var enumerator = bookmakersEl.EnumerateArray();
|
||||
if (enumerator.MoveNext())
|
||||
{
|
||||
selectedBookmaker = enumerator.Current;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found || !selectedBookmaker.TryGetProperty("bets", out var betsEl))
|
||||
continue;
|
||||
|
||||
foreach (var bet in betsEl.EnumerateArray())
|
||||
{
|
||||
string betName = bet.TryGetProperty("name", out var nameEl) ? nameEl.GetString() : "";
|
||||
if (string.IsNullOrEmpty(betName) || !bet.TryGetProperty("values", out var valuesEl))
|
||||
continue;
|
||||
|
||||
switch (betName)
|
||||
{
|
||||
case "Match Winner":
|
||||
foreach (var v in valuesEl.EnumerateArray())
|
||||
{
|
||||
string val = GetOddValueString(v, "value");
|
||||
string odd = GetOddValueString(v, "odd");
|
||||
if (val == "Home") row["Quota Casa"] = odd;
|
||||
else if (val == "Draw") row["Quota Pareggio"] = odd;
|
||||
else if (val == "Away") row["Quota Trasferta"] = odd;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Goals Over/Under":
|
||||
foreach (var v in valuesEl.EnumerateArray())
|
||||
{
|
||||
string val = GetOddValueString(v, "value");
|
||||
string odd = GetOddValueString(v, "odd");
|
||||
if (val == "Over 2.5") row["Over 2.5"] = odd;
|
||||
else if (val == "Under 2.5") row["Under 2.5"] = odd;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Both Teams Score":
|
||||
foreach (var v in valuesEl.EnumerateArray())
|
||||
{
|
||||
string val = GetOddValueString(v, "value");
|
||||
string odd = GetOddValueString(v, "odd");
|
||||
if (val == "Yes") row["BTTS Sì"] = odd;
|
||||
else if (val == "No") row["BTTS No"] = odd;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Double Chance":
|
||||
foreach (var v in valuesEl.EnumerateArray())
|
||||
{
|
||||
string val = GetOddValueString(v, "value");
|
||||
string odd = GetOddValueString(v, "odd");
|
||||
if (val == "Home/Draw") row["Doppia Casa/X"] = odd;
|
||||
else if (val == "Home/Away") row["Doppia Casa/Trasf"] = odd;
|
||||
else if (val == "Draw/Away") row["Doppia X/Trasf"] = odd;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_database.LogError("elaborazione quote per singola partita", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_database.LogError("parsing quote nella tabella", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Estrae un valore stringa da un JsonElement in modo sicuro
|
||||
/// </summary>
|
||||
private string GetOddValueString(JsonElement element, string propertyName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!element.TryGetProperty(propertyName, out var prop))
|
||||
return "";
|
||||
|
||||
switch (prop.ValueKind)
|
||||
{
|
||||
case JsonValueKind.String:
|
||||
return prop.GetString() ?? "";
|
||||
case JsonValueKind.Number:
|
||||
return prop.GetDecimal().ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||
default:
|
||||
return prop.ToString();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elabora le risposte API non elaborate presenti nel database
|
||||
/// </summary>
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Threading.Tasks;
|
||||
using RestSharp;
|
||||
using HorseRacingPredictor.Football.Database;
|
||||
using HorseRacingPredictor.Football.API;
|
||||
using League = HorseRacingPredictor.Football.API.League;
|
||||
using Fixture = HorseRacingPredictor.Football.API.Fixture;
|
||||
|
||||
@@ -41,26 +40,33 @@ namespace HorseRacingPredictor.Football.Manager
|
||||
/// </summary>
|
||||
protected RestResponse ExecuteRequest(string endpoint, string apiType = null, string parameters = null)
|
||||
{
|
||||
string url = $"{BaseUrl}/{endpoint}";
|
||||
var response = ExecuteApiRequest(url, ApiKey, KeyHeader, HostHeader, HostValue);
|
||||
|
||||
// Salva la risposta su file per debug (non bloccare in caso di errore)
|
||||
try
|
||||
{
|
||||
string url = $"{BaseUrl}/{endpoint}";
|
||||
var response = ExecuteApiRequest(url, ApiKey, KeyHeader, HostHeader, HostValue);
|
||||
|
||||
// Salva la risposta su file per debug
|
||||
SaveResponseToFile(url, response.Content, "FootballApiResponses");
|
||||
|
||||
// Salva la risposta nel database
|
||||
if (apiType != null)
|
||||
{
|
||||
_apiResponseRepository.InsertApiResponse(apiType, endpoint, parameters, response);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante la richiesta all'endpoint {endpoint}: {ex.Message}", ex);
|
||||
Console.WriteLine($"Avviso: impossibile salvare risposta su file: {ex.Message}");
|
||||
}
|
||||
|
||||
// Salva la risposta nel database (non bloccare in caso di errore)
|
||||
if (apiType != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_apiResponseRepository.InsertApiResponse(apiType, endpoint, parameters, response);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Avviso: impossibile salvare risposta nel database: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,26 +74,33 @@ namespace HorseRacingPredictor.Football.Manager
|
||||
/// </summary>
|
||||
protected async Task<RestResponse> ExecuteRequestAsync(string endpoint, string apiType = null, string parameters = null)
|
||||
{
|
||||
string url = $"{BaseUrl}/{endpoint}";
|
||||
var response = await ExecuteApiRequestAsync(url, ApiKey, KeyHeader, HostHeader, HostValue);
|
||||
|
||||
// Salva la risposta su file per debug (non bloccare in caso di errore)
|
||||
try
|
||||
{
|
||||
string url = $"{BaseUrl}/{endpoint}";
|
||||
var response = await ExecuteApiRequestAsync(url, ApiKey, KeyHeader, HostHeader, HostValue);
|
||||
|
||||
// Salva la risposta su file per debug
|
||||
SaveResponseToFile(url, response.Content, "FootballApiResponses");
|
||||
|
||||
// Salva la risposta nel database
|
||||
if (apiType != null)
|
||||
{
|
||||
_apiResponseRepository.InsertApiResponse(apiType, endpoint, parameters, response);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante la richiesta all'endpoint {endpoint}: {ex.Message}", ex);
|
||||
Console.WriteLine($"Avviso: impossibile salvare risposta su file: {ex.Message}");
|
||||
}
|
||||
|
||||
// Salva la risposta nel database (non bloccare in caso di errore)
|
||||
if (apiType != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_apiResponseRepository.InsertApiResponse(apiType, endpoint, parameters, response);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Avviso: impossibile salvare risposta nel database: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
#region Leagues
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using RestSharp;
|
||||
|
||||
namespace HorseRacingPredictor.HorseRacing.API
|
||||
{
|
||||
/// <summary>
|
||||
/// Client per The Racing API (theracingapi.com)
|
||||
/// Utilizza HTTP Basic Authentication
|
||||
/// </summary>
|
||||
internal class RacingApiClient
|
||||
{
|
||||
private const string BaseUrl = "https://api.theracingapi.com/v1";
|
||||
private const int DefaultDelay = 1100; // Rate limit: 1 req/sec per Free plan
|
||||
|
||||
private readonly string _username;
|
||||
private readonly string _password;
|
||||
|
||||
public RacingApiClient(string username, string password)
|
||||
{
|
||||
_username = username;
|
||||
_password = password;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue una richiesta GET autenticata con HTTP Basic Auth
|
||||
/// </summary>
|
||||
private RestResponse ExecuteRequest(string endpoint, int delay = DefaultDelay)
|
||||
{
|
||||
string url = $"{BaseUrl}/{endpoint}";
|
||||
var client = new RestClient(url);
|
||||
var request = new RestRequest();
|
||||
|
||||
string credentials = Convert.ToBase64String(
|
||||
Encoding.ASCII.GetBytes($"{_username}:{_password}"));
|
||||
request.AddHeader("Authorization", $"Basic {credentials}");
|
||||
|
||||
try
|
||||
{
|
||||
var response = client.Execute(request);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
throw new Exception(
|
||||
$"Errore API Racing ({(int)response.StatusCode}): {response.StatusDescription}");
|
||||
}
|
||||
|
||||
if (delay > 0)
|
||||
Thread.Sleep(delay);
|
||||
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex) when (!(ex.Message.StartsWith("Errore API Racing")))
|
||||
{
|
||||
throw new Exception($"Errore durante la richiesta a Racing API: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene le racecard (programma corse) per oggi o domani
|
||||
/// </summary>
|
||||
/// <param name="day">"today" oppure "tomorrow"</param>
|
||||
/// <param name="regionCodes">Codici regione opzionali (es. "gb", "ire")</param>
|
||||
public RestResponse GetRacecardsFree(string day = "today", string[] regionCodes = null)
|
||||
{
|
||||
var sb = new StringBuilder("racecards/free?");
|
||||
sb.Append($"day={day}");
|
||||
|
||||
if (regionCodes != null && regionCodes.Length > 0)
|
||||
{
|
||||
foreach (var rc in regionCodes)
|
||||
sb.Append($"®ion_codes={rc}");
|
||||
}
|
||||
|
||||
return ExecuteRequest(sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene le racecard standard per oggi o domani
|
||||
/// </summary>
|
||||
public RestResponse GetRacecardsStandard(string day = "today", string[] regionCodes = null)
|
||||
{
|
||||
var sb = new StringBuilder("racecards/standard?");
|
||||
sb.Append($"day={day}");
|
||||
|
||||
if (regionCodes != null && regionCodes.Length > 0)
|
||||
{
|
||||
foreach (var rc in regionCodes)
|
||||
sb.Append($"®ion_codes={rc}");
|
||||
}
|
||||
|
||||
return ExecuteRequest(sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene i risultati per un intervallo di date
|
||||
/// </summary>
|
||||
public RestResponse GetResults(DateTime startDate, DateTime endDate, string[] regionCodes = null)
|
||||
{
|
||||
var sb = new StringBuilder("results?");
|
||||
sb.Append($"start_date={startDate:yyyy-MM-dd}");
|
||||
sb.Append($"&end_date={endDate:yyyy-MM-dd}");
|
||||
|
||||
if (regionCodes != null && regionCodes.Length > 0)
|
||||
{
|
||||
foreach (var rc in regionCodes)
|
||||
sb.Append($"®ion={rc}");
|
||||
}
|
||||
|
||||
return ExecuteRequest(sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene l'elenco delle regioni disponibili
|
||||
/// </summary>
|
||||
public RestResponse GetRegions()
|
||||
{
|
||||
return ExecuteRequest("courses/regions");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene l'elenco dei corsi per le regioni specificate
|
||||
/// </summary>
|
||||
public RestResponse GetCourses(string[] regionCodes = null)
|
||||
{
|
||||
var sb = new StringBuilder("courses?");
|
||||
if (regionCodes != null && regionCodes.Length > 0)
|
||||
{
|
||||
foreach (var rc in regionCodes)
|
||||
sb.Append($"®ion_codes={rc}");
|
||||
}
|
||||
|
||||
return ExecuteRequest(sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
266
HorseRacingPredictor/HorseRacingPredictor/HorseRacing/Main.cs
Normal file
266
HorseRacingPredictor/HorseRacingPredictor/HorseRacing/Main.cs
Normal file
@@ -0,0 +1,266 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using HorseRacingPredictor.HorseRacing.API;
|
||||
|
||||
namespace HorseRacingPredictor.HorseRacing
|
||||
{
|
||||
/// <summary>
|
||||
/// Gestore centralizzato per la sezione Corse dei Cavalli.
|
||||
/// Scarica i dati da The Racing API e li converte in DataTable.
|
||||
/// </summary>
|
||||
public class Main
|
||||
{
|
||||
private RacingApiClient _client;
|
||||
|
||||
public Main(string username, string password)
|
||||
{
|
||||
_client = new RacingApiClient(username, password);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggiorna le credenziali API
|
||||
/// </summary>
|
||||
public void UpdateCredentials(string username, string password)
|
||||
{
|
||||
_client = new RacingApiClient(username, password);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scarica le racecard (programma corse) per oggi o domani e le restituisce come DataTable
|
||||
/// </summary>
|
||||
public DataTable GetRacecards(string day, IProgress<int> progress = null, IProgress<string> status = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
status?.Report("Connessione a The Racing API...");
|
||||
progress?.Report(10);
|
||||
|
||||
var response = _client.GetRacecardsFree(day);
|
||||
progress?.Report(60);
|
||||
|
||||
status?.Report("Elaborazione racecard...");
|
||||
var table = ParseRacecardsResponse(response.Content);
|
||||
progress?.Report(100);
|
||||
|
||||
status?.Report($"Trovate {table.Rows.Count} corse");
|
||||
return table;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
status?.Report($"Errore: {ex.Message}");
|
||||
return CreateEmptyRacecardsTable();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scarica i risultati per un intervallo di date
|
||||
/// </summary>
|
||||
public DataTable GetResults(DateTime startDate, DateTime endDate,
|
||||
IProgress<int> progress = null, IProgress<string> status = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
status?.Report("Scaricamento risultati...");
|
||||
progress?.Report(10);
|
||||
|
||||
var response = _client.GetResults(startDate, endDate);
|
||||
progress?.Report(60);
|
||||
|
||||
status?.Report("Elaborazione risultati...");
|
||||
var table = ParseResultsResponse(response.Content);
|
||||
progress?.Report(100);
|
||||
|
||||
status?.Report($"Trovati {table.Rows.Count} risultati");
|
||||
return table;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
status?.Report($"Errore: {ex.Message}");
|
||||
return CreateEmptyResultsTable();
|
||||
}
|
||||
}
|
||||
|
||||
#region DataTable creation
|
||||
|
||||
private DataTable CreateEmptyRacecardsTable()
|
||||
{
|
||||
var dt = new DataTable();
|
||||
dt.Columns.Add("Ora", typeof(string));
|
||||
dt.Columns.Add("Ippodromo", typeof(string));
|
||||
dt.Columns.Add("Regione", typeof(string));
|
||||
dt.Columns.Add("Corsa", typeof(string));
|
||||
dt.Columns.Add("Distanza", typeof(string));
|
||||
dt.Columns.Add("Tipo", typeof(string));
|
||||
dt.Columns.Add("Classe", typeof(string));
|
||||
dt.Columns.Add("Terreno", typeof(string));
|
||||
dt.Columns.Add("N. Corridori", typeof(int));
|
||||
dt.Columns.Add("Età", typeof(string));
|
||||
dt.Columns.Add("Premio", typeof(string));
|
||||
return dt;
|
||||
}
|
||||
|
||||
private DataTable CreateEmptyResultsTable()
|
||||
{
|
||||
var dt = new DataTable();
|
||||
dt.Columns.Add("Data", typeof(string));
|
||||
dt.Columns.Add("Ippodromo", typeof(string));
|
||||
dt.Columns.Add("Corsa", typeof(string));
|
||||
dt.Columns.Add("Distanza", typeof(string));
|
||||
dt.Columns.Add("Terreno", typeof(string));
|
||||
dt.Columns.Add("1° Classificato", typeof(string));
|
||||
dt.Columns.Add("2° Classificato", typeof(string));
|
||||
dt.Columns.Add("3° Classificato", typeof(string));
|
||||
dt.Columns.Add("Fantino 1°", typeof(string));
|
||||
dt.Columns.Add("SP 1°", typeof(string));
|
||||
return dt;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON Parsing
|
||||
|
||||
private DataTable ParseRacecardsResponse(string json)
|
||||
{
|
||||
var dt = CreateEmptyRacecardsTable();
|
||||
if (string.IsNullOrEmpty(json)) return dt;
|
||||
|
||||
try
|
||||
{
|
||||
using (var doc = JsonDocument.Parse(json))
|
||||
{
|
||||
var root = doc.RootElement;
|
||||
|
||||
if (!root.TryGetProperty("racecards", out var racecardsEl))
|
||||
return dt;
|
||||
|
||||
foreach (var rc in racecardsEl.EnumerateArray())
|
||||
{
|
||||
try
|
||||
{
|
||||
var row = dt.NewRow();
|
||||
|
||||
row["Ora"] = GetString(rc, "off_time", "");
|
||||
row["Ippodromo"] = GetString(rc, "course", "");
|
||||
row["Regione"] = GetString(rc, "region", "");
|
||||
row["Corsa"] = GetString(rc, "race_name", "");
|
||||
row["Distanza"] = GetString(rc, "distance", "");
|
||||
row["Tipo"] = GetString(rc, "type", "");
|
||||
row["Classe"] = GetString(rc, "race_class", "");
|
||||
row["Terreno"] = GetString(rc, "going", "");
|
||||
row["Età"] = GetString(rc, "age_band", "");
|
||||
row["Premio"] = GetString(rc, "prize", "");
|
||||
|
||||
if (rc.TryGetProperty("runners", out var runnersEl) &&
|
||||
runnersEl.ValueKind == JsonValueKind.Array)
|
||||
{
|
||||
row["N. Corridori"] = runnersEl.GetArrayLength();
|
||||
}
|
||||
else if (rc.TryGetProperty("field_size", out var fsEl) &&
|
||||
fsEl.ValueKind == JsonValueKind.Number)
|
||||
{
|
||||
row["N. Corridori"] = fsEl.GetInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
row["N. Corridori"] = 0;
|
||||
}
|
||||
|
||||
dt.Rows.Add(row);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Salta righe problematiche
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Restituisci tabella vuota in caso di errore di parsing
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
private DataTable ParseResultsResponse(string json)
|
||||
{
|
||||
var dt = CreateEmptyResultsTable();
|
||||
if (string.IsNullOrEmpty(json)) return dt;
|
||||
|
||||
try
|
||||
{
|
||||
using (var doc = JsonDocument.Parse(json))
|
||||
{
|
||||
var root = doc.RootElement;
|
||||
|
||||
if (!root.TryGetProperty("results", out var resultsEl))
|
||||
return dt;
|
||||
|
||||
foreach (var res in resultsEl.EnumerateArray())
|
||||
{
|
||||
try
|
||||
{
|
||||
var row = dt.NewRow();
|
||||
|
||||
row["Data"] = GetString(res, "date", "");
|
||||
row["Ippodromo"] = GetString(res, "course", "");
|
||||
row["Corsa"] = GetString(res, "race_name", "");
|
||||
row["Distanza"] = GetString(res, "distance", "");
|
||||
row["Terreno"] = GetString(res, "going", "");
|
||||
|
||||
if (res.TryGetProperty("runners", out var runnersEl) &&
|
||||
runnersEl.ValueKind == JsonValueKind.Array)
|
||||
{
|
||||
int idx = 0;
|
||||
foreach (var runner in runnersEl.EnumerateArray())
|
||||
{
|
||||
var pos = GetString(runner, "position", "");
|
||||
if (pos == "1" || idx == 0)
|
||||
{
|
||||
row["1° Classificato"] = GetString(runner, "horse", "");
|
||||
row["Fantino 1°"] = GetString(runner, "jockey", "");
|
||||
row["SP 1°"] = GetString(runner, "sp", "");
|
||||
}
|
||||
else if (pos == "2" || idx == 1)
|
||||
{
|
||||
row["2° Classificato"] = GetString(runner, "horse", "");
|
||||
}
|
||||
else if (pos == "3" || idx == 2)
|
||||
{
|
||||
row["3° Classificato"] = GetString(runner, "horse", "");
|
||||
}
|
||||
idx++;
|
||||
if (idx >= 3) break;
|
||||
}
|
||||
}
|
||||
|
||||
dt.Rows.Add(row);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Salta righe problematiche
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Restituisci tabella vuota in caso di errore di parsing
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
private static string GetString(JsonElement el, string property, string defaultValue)
|
||||
{
|
||||
if (el.TryGetProperty(property, out var prop) && prop.ValueKind == JsonValueKind.String)
|
||||
return prop.GetString() ?? defaultValue;
|
||||
if (el.TryGetProperty(property, out prop) && prop.ValueKind == JsonValueKind.Number)
|
||||
return prop.ToString();
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -5,17 +5,15 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using HorseRacingPredictor.Horses.ML;
|
||||
|
||||
namespace HorseRacingPredictor.Horses
|
||||
{
|
||||
internal class Calculator
|
||||
{
|
||||
private readonly MachineLearningService _mlService;
|
||||
|
||||
public Calculator()
|
||||
{
|
||||
_mlService = new MachineLearningService();
|
||||
// Machine learning service removed or unavailable in this build.
|
||||
// Keep constructor minimal.
|
||||
}
|
||||
|
||||
public int CalculateRating1(DataRow row)
|
||||
@@ -168,52 +166,15 @@ namespace HorseRacingPredictor.Horses
|
||||
/// </summary>
|
||||
public int CalculateMLRating(DataRow row)
|
||||
{
|
||||
// Machine learning component removed: fall back to deterministic rating
|
||||
try
|
||||
{
|
||||
// Prepara l'input per il modello ML
|
||||
var input = new ModelInput
|
||||
{
|
||||
Age = GetFloatValueOrDefault(row, "Age"),
|
||||
HandicapRating = GetFloatValueOrDefault(row, "Handicap Rating"),
|
||||
Weight = GetFloatValueOrDefault(row, "Weight"),
|
||||
WeightCarried = GetFloatValueOrDefault(row, "Weight Carried"),
|
||||
Barrier = GetFloatValueOrDefault(row, "Barrier"),
|
||||
CareerRuns = GetFloatValueOrDefault(row, "Career Runs"),
|
||||
CareerWins = GetFloatValueOrDefault(row, "Career Wins"),
|
||||
CareerStrikeRate = GetFloatValueOrDefault(row, "Career Strike Rate"),
|
||||
CareerROI = GetFloatValueOrDefault(row, "Career ROI"),
|
||||
ThisTrackRuns = GetFloatValueOrDefault(row, "This Track Runs"),
|
||||
ThisTrackWins = GetFloatValueOrDefault(row, "This Track Wins"),
|
||||
ThisTrackStrikeRate = GetFloatValueOrDefault(row, "This Track Strike Rate"),
|
||||
ThisDistanceRuns = GetFloatValueOrDefault(row, "This Distance Runs"),
|
||||
ThisDistanceWins = GetFloatValueOrDefault(row, "This Distance Wins"),
|
||||
ThisDistanceStrikeRate = GetFloatValueOrDefault(row, "This Distance Strike Rate"),
|
||||
JockeyLast100Wins = GetFloatValueOrDefault(row, "Jockey Last 100 Wins"),
|
||||
JockeyLast100StrikeRate = GetFloatValueOrDefault(row, "Jockey Last 100 Strike Rate"),
|
||||
TrainerLast100Wins = GetFloatValueOrDefault(row, "Trainer Last 100 Wins"),
|
||||
TrainerLast100StrikeRate = GetFloatValueOrDefault(row, "Trainer Last 100 Strike Rate"),
|
||||
BestFixedOdds = GetFloatValueOrDefault(row, "Best Fixed Odds")
|
||||
};
|
||||
|
||||
// Effettua la previsione usando il modello ML
|
||||
var output = _mlService.PredictFinishPosition(input);
|
||||
|
||||
// Il rating ML è inversamente proporzionale alla posizione prevista
|
||||
// Migliore è la posizione prevista (più vicina a 1), più alto sarà il rating
|
||||
double mlRating = 100 * (1.0 / Math.Max(1, output.PredictedPosition));
|
||||
|
||||
// Aggiusta il rating in base alla probabilità di vittoria
|
||||
mlRating = mlRating * (0.6 + (output.WinProbability * 0.4));
|
||||
|
||||
return (int)Math.Min(100, Math.Max(0, mlRating));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Errore nel calcolo del rating ML: {ex.Message}");
|
||||
|
||||
// In caso di errore, ritorna un rating basato sul metodo standard
|
||||
return CalculateRating1(row);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private double GetValueOrDefault(DataRow row, string columnName)
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace HorseRacingPredictor.Horses.ML
|
||||
{
|
||||
/// <summary>
|
||||
/// Classe che contiene il risultato della previsione per un singolo cavallo in una corsa.
|
||||
/// </summary>
|
||||
public class HorseRacePrediction
|
||||
{
|
||||
// Informazioni identificative
|
||||
public string HorseId { get; set; }
|
||||
public string HorseName { get; set; }
|
||||
public string RaceMeeting { get; set; }
|
||||
public int RaceNumber { get; set; }
|
||||
public DateTime RaceDate { get; set; }
|
||||
|
||||
// Risultati della previsione
|
||||
public float PredictedPosition { get; set; }
|
||||
public float WinProbability { get; set; }
|
||||
public float PlaceProbability { get; set; }
|
||||
|
||||
// Rating ML calcolato (combinazione di probabilità e altri fattori)
|
||||
public int MLRating { get; set; }
|
||||
|
||||
// Quota attuale per valutazione valore
|
||||
public float CurrentOdds { get; set; }
|
||||
|
||||
// Valore calcolato (rapporto tra probabilità e quota)
|
||||
public float Value => WinProbability > 0 ? (WinProbability * 100) / (1 / CurrentOdds) : 0;
|
||||
|
||||
// Indicazione se questo cavallo è considerato di valore
|
||||
public bool IsValueBet => Value > 1.1f;
|
||||
|
||||
// Posizione reale del cavallo
|
||||
public string ActualPosition { get; set; }
|
||||
|
||||
// Indicazione se la previsione è accurata
|
||||
public bool IsAccuratePrediction { get; set; }
|
||||
|
||||
// Metodo per valutare l'accuratezza della previsione
|
||||
public void EvaluateAccuracy()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ActualPosition) && int.TryParse(ActualPosition, out int actualPos))
|
||||
{
|
||||
IsAccuratePrediction = Math.Abs(actualPos - PredictedPosition) <= 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,573 +0,0 @@
|
||||
using Microsoft.ML;
|
||||
using Microsoft.ML.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Data.SqlClient;
|
||||
|
||||
namespace HorseRacingPredictor.Horses.ML
|
||||
{
|
||||
/// <summary>
|
||||
/// Servizio principale per l'implementazione del machine learning
|
||||
/// </summary>
|
||||
public class MachineLearningService
|
||||
{
|
||||
private readonly MLContext _mlContext;
|
||||
private ITransformer _trainedModel;
|
||||
private readonly string _modelPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Models", "HorseRaceModel.zip");
|
||||
|
||||
public string ConnectionString { get; set; }
|
||||
|
||||
public MachineLearningService(string connectionString = null)
|
||||
{
|
||||
_mlContext = new MLContext(seed: 42);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(_modelPath));
|
||||
ConnectionString = connectionString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Carica un modello ML esistente da file
|
||||
/// </summary>
|
||||
public void LoadModel()
|
||||
{
|
||||
if (!File.Exists(_modelPath))
|
||||
throw new FileNotFoundException($"[ML] Modello non trovato: {_modelPath}");
|
||||
|
||||
Console.WriteLine($"[ML] Caricamento modello da: {_modelPath}");
|
||||
_trainedModel = _mlContext.Model.Load(_modelPath, out _);
|
||||
Console.WriteLine("[ML] Modello ML caricato correttamente.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Salva il modello addestrato su file
|
||||
/// </summary>
|
||||
public void SaveModel(ITransformer model)
|
||||
{
|
||||
Console.WriteLine($"[ML] Salvataggio modello in: {_modelPath}");
|
||||
_mlContext.Model.Save(model, null, _modelPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene i dati di training dal database e addestra un modello ML
|
||||
/// </summary>
|
||||
public void TrainModel(string connectionString)
|
||||
{
|
||||
// Imposta a 'true' per ricreare sempre il modello (default).
|
||||
// Per NON ricreare il modello ad ogni esecuzione, commenta la riga seguente:
|
||||
bool alwaysRetrain = true;
|
||||
// bool alwaysRetrain = false;
|
||||
|
||||
if (!alwaysRetrain && File.Exists(_modelPath))
|
||||
{
|
||||
Console.WriteLine("[ML] Modello già esistente. Caricamento modello da file...");
|
||||
LoadModel();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine("[ML] Inizio caricamento dati di training dal database...");
|
||||
var trainingData = LoadTrainingDataFromDatabase(connectionString);
|
||||
|
||||
if (trainingData.Count == 0)
|
||||
{
|
||||
Console.WriteLine("[ML][ERRORE] Nessun dato di training disponibile nel database.");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine($"[ML] Numero record caricati per il training: {trainingData.Count}");
|
||||
|
||||
var dataView = _mlContext.Data.LoadFromEnumerable(trainingData);
|
||||
|
||||
// Suddividi i dati in train e test (80% train, 20% test)
|
||||
var split = _mlContext.Data.TrainTestSplit(dataView, testFraction: 0.2, seed: 42);
|
||||
|
||||
// Costruisci la pipeline di training
|
||||
var pipeline = _mlContext.Transforms.Concatenate("Features",
|
||||
"Age", "HandicapRating", "Weight", "WeightCarried", "Barrier",
|
||||
"CareerRuns", "CareerWins", "CareerStrikeRate", "CareerROI",
|
||||
"ThisTrackRuns", "ThisTrackWins", "ThisTrackStrikeRate",
|
||||
"ThisDistanceRuns", "ThisDistanceWins", "ThisDistanceStrikeRate",
|
||||
"JockeyLast100Wins", "JockeyLast100StrikeRate",
|
||||
"TrainerLast100Wins", "TrainerLast100StrikeRate", "BestFixedOdds",
|
||||
"Rating1", "Rating2", "Rating3", "Rating4", "Rating5"
|
||||
// Qui puoi aggiungere nuove feature create o derivate
|
||||
)
|
||||
.Append(_mlContext.Transforms.NormalizeMinMax("Features"))
|
||||
.Append(_mlContext.Regression.Trainers.FastTree(
|
||||
labelColumnName: "FinishPosition",
|
||||
featureColumnName: "Features",
|
||||
numberOfTrees: 200, // Aumentato per maggiore accuratezza
|
||||
numberOfLeaves: 32, // Più foglie per maggiore complessità
|
||||
minimumExampleCountPerLeaf: 5, // Più sensibile ai dettagli
|
||||
learningRate: 0.15f // Puoi sperimentare anche questo parametro
|
||||
));
|
||||
|
||||
Console.WriteLine("[ML] Inizio addestramento del modello...");
|
||||
_trainedModel = pipeline.Fit(split.TrainSet);
|
||||
Console.WriteLine("[ML] Addestramento completato.");
|
||||
|
||||
// Valuta sul training set
|
||||
var trainMetrics = _mlContext.Regression.Evaluate(_trainedModel.Transform(split.TrainSet), labelColumnName: "FinishPosition");
|
||||
// Valuta sul test set
|
||||
var testMetrics = _mlContext.Regression.Evaluate(_trainedModel.Transform(split.TestSet), labelColumnName: "FinishPosition");
|
||||
|
||||
// Cross-validation
|
||||
var cvResults = _mlContext.Regression.CrossValidate(data: dataView, estimator: pipeline, numberOfFolds: 5, labelColumnName: "FinishPosition");
|
||||
var avgRSquared = cvResults.Average(fold => fold.Metrics.RSquared);
|
||||
Console.WriteLine($"RSquared medio (cross-validation): {avgRSquared:F4}");
|
||||
|
||||
SaveModel(_trainedModel);
|
||||
Console.WriteLine($"[ML] Modello salvato in: {_modelPath}");
|
||||
|
||||
Console.WriteLine("[ML] Metriche di valutazione (TRAIN):");
|
||||
Console.WriteLine($"[ML] - RSquared: {trainMetrics.RSquared:F4}");
|
||||
Console.WriteLine($"[ML] - MAE: {trainMetrics.MeanAbsoluteError:F4}");
|
||||
Console.WriteLine($"[ML] - MSE: {trainMetrics.MeanSquaredError:F4}");
|
||||
Console.WriteLine($"[ML] - RMSE: {trainMetrics.RootMeanSquaredError:F4}");
|
||||
|
||||
Console.WriteLine("[ML] Metriche di valutazione (TEST):");
|
||||
Console.WriteLine($"[ML] - RSquared: {testMetrics.RSquared:F4}");
|
||||
Console.WriteLine($"[ML] - MAE: {testMetrics.MeanAbsoluteError:F4}");
|
||||
Console.WriteLine($"[ML] - MSE: {testMetrics.MeanSquaredError:F4}");
|
||||
Console.WriteLine($"[ML] - RMSE: {testMetrics.RootMeanSquaredError:F4}");
|
||||
|
||||
var predictions = _trainedModel.Transform(split.TestSet);
|
||||
var actuals = _mlContext.Data.CreateEnumerable<ModelInput>(split.TestSet, false).ToList();
|
||||
var preds = _mlContext.Data.CreateEnumerable<ModelOutput>(predictions, false).ToList();
|
||||
|
||||
int top3Correct = actuals.Zip(preds, (a, p) => (a, p))
|
||||
.Count(x => x.a.FinishPosition <= 3 && x.p.PredictedPosition <= 3);
|
||||
double accuracyTop3 = (double)top3Correct / actuals.Count;
|
||||
Console.WriteLine($"Percentuale cavalli previsti nei primi 3: {accuracyTop3:P2}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[ML][ERRORE] Errore durante l'addestramento del modello: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Carica i dati di training dal database
|
||||
/// </summary>
|
||||
private List<ModelInput> LoadTrainingDataFromDatabase(string connectionString)
|
||||
{
|
||||
var trainingData = new List<ModelInput>();
|
||||
var calculator = new HorseRacingPredictor.Horses.Calculator();
|
||||
int skippedRows = 0;
|
||||
int rating1Errors = 0, rating2Errors = 0, rating3Errors = 0, rating4Errors = 0, rating5Errors = 0;
|
||||
|
||||
try
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
string query = @"
|
||||
SELECT
|
||||
CASE WHEN ISNUMERIC(FinishResult) = 1 THEN CAST(FinishResult AS FLOAT) ELSE 999 END AS FinishPosition,
|
||||
COALESCE(Age, 0) AS Age,
|
||||
COALESCE(HandicapRating, 0) AS HandicapRating,
|
||||
COALESCE(Weight, 0) AS Weight,
|
||||
COALESCE(WeightCarried, 0) AS WeightCarried,
|
||||
COALESCE(Barrier, 0) AS Barrier,
|
||||
COALESCE(CareerRuns, 0) AS CareerRuns,
|
||||
COALESCE(CareerWins, 0) AS CareerWins,
|
||||
COALESCE(CareerStrikeRate, 0) AS CareerStrikeRate,
|
||||
COALESCE(CareerROI, 0) AS CareerROI,
|
||||
COALESCE(ThisTrackRuns, 0) AS ThisTrackRuns,
|
||||
COALESCE(ThisTrackWins, 0) AS ThisTrackWins,
|
||||
COALESCE(ThisTrackStrikeRate, 0) AS ThisTrackStrikeRate,
|
||||
COALESCE(ThisDistanceRuns, 0) AS ThisDistanceRuns,
|
||||
COALESCE(ThisDistanceWins, 0) AS ThisDistanceWins,
|
||||
COALESCE(ThisDistanceStrikeRate, 0) AS ThisDistanceStrikeRate,
|
||||
COALESCE(JockeyLast100Wins, 0) AS JockeyLast100Wins,
|
||||
COALESCE(JockeyLast100StrikeRate, 0) AS JockeyLast100StrikeRate,
|
||||
COALESCE(TrainerLast100Wins, 0) AS TrainerLast100Wins,
|
||||
COALESCE(TrainerLast100StrikeRate, 0) AS TrainerLast100StrikeRate,
|
||||
COALESCE(BestFixedOdds, 0) AS BestFixedOdds,
|
||||
COALESCE(Gender, '') AS Gender
|
||||
FROM Races
|
||||
WHERE ISNUMERIC(FinishResult) = 1
|
||||
AND FinishResult IS NOT NULL
|
||||
AND FinishResult <> ''";
|
||||
|
||||
using (var command = new SqlCommand(query, connection))
|
||||
{
|
||||
using (var adapter = new SqlDataAdapter(command))
|
||||
{
|
||||
var table = new System.Data.DataTable();
|
||||
adapter.Fill(table);
|
||||
|
||||
foreach (System.Data.DataRow row in table.Rows)
|
||||
{
|
||||
try {
|
||||
float finishPos = Convert.ToSingle(row["FinishPosition"]);
|
||||
if (finishPos >= 15 || finishPos <= 0) {
|
||||
skippedRows++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calcola i rating con gestione degli errori e sostituzione con valori predefiniti
|
||||
float rating1 = 0, rating2 = 0, rating3 = 0, rating4 = 0, rating5 = 0;
|
||||
|
||||
try {
|
||||
rating1 = (float)calculator.CalculateRating1(row);
|
||||
if (float.IsNaN(rating1) || float.IsInfinity(rating1)) {
|
||||
rating1 = 0;
|
||||
rating1Errors++;
|
||||
}
|
||||
} catch (Exception) {
|
||||
rating1Errors++;
|
||||
}
|
||||
|
||||
try {
|
||||
rating2 = (float)calculator.CalculateRating2(row);
|
||||
if (float.IsNaN(rating2) || float.IsInfinity(rating2)) {
|
||||
rating2 = 0;
|
||||
rating2Errors++;
|
||||
}
|
||||
} catch (Exception) {
|
||||
rating2Errors++;
|
||||
}
|
||||
|
||||
try {
|
||||
rating3 = (float)calculator.CalculateRating3(row);
|
||||
if (float.IsNaN(rating3) || float.IsInfinity(rating3)) {
|
||||
rating3 = 0;
|
||||
rating3Errors++;
|
||||
}
|
||||
} catch (Exception) {
|
||||
rating3Errors++;
|
||||
}
|
||||
|
||||
try {
|
||||
rating4 = (float)calculator.CalculateRating4(row);
|
||||
if (float.IsNaN(rating4) || float.IsInfinity(rating4)) {
|
||||
rating4 = 0;
|
||||
rating4Errors++;
|
||||
}
|
||||
} catch (Exception) {
|
||||
rating4Errors++;
|
||||
}
|
||||
|
||||
try {
|
||||
rating5 = (float)calculator.CalculateRating5(row);
|
||||
if (float.IsNaN(rating5) || float.IsInfinity(rating5)) {
|
||||
rating5 = 0;
|
||||
rating5Errors++;
|
||||
}
|
||||
} catch (Exception) {
|
||||
rating5Errors++;
|
||||
}
|
||||
|
||||
// Usa SafeConvert per tutte le conversioni
|
||||
trainingData.Add(new ModelInput
|
||||
{
|
||||
FinishPosition = finishPos,
|
||||
Age = SafeConvert.ToSingle(row["Age"]),
|
||||
HandicapRating = SafeConvert.ToSingle(row["HandicapRating"]),
|
||||
Weight = SafeConvert.ToSingle(row["Weight"]),
|
||||
WeightCarried = SafeConvert.ToSingle(row["WeightCarried"]),
|
||||
Barrier = SafeConvert.ToSingle(row["Barrier"]),
|
||||
CareerRuns = SafeConvert.ToSingle(row["CareerRuns"]),
|
||||
CareerWins = SafeConvert.ToSingle(row["CareerWins"]),
|
||||
CareerStrikeRate = SafeConvert.ToSingle(row["CareerStrikeRate"]),
|
||||
CareerROI = SafeConvert.ToSingle(row["CareerROI"]),
|
||||
ThisTrackRuns = SafeConvert.ToSingle(row["ThisTrackRuns"]),
|
||||
ThisTrackWins = SafeConvert.ToSingle(row["ThisTrackWins"]),
|
||||
ThisTrackStrikeRate = SafeConvert.ToSingle(row["ThisTrackStrikeRate"]),
|
||||
ThisDistanceRuns = SafeConvert.ToSingle(row["ThisDistanceRuns"]),
|
||||
ThisDistanceWins = SafeConvert.ToSingle(row["ThisDistanceWins"]),
|
||||
ThisDistanceStrikeRate = SafeConvert.ToSingle(row["ThisDistanceStrikeRate"]),
|
||||
JockeyLast100Wins = SafeConvert.ToSingle(row["JockeyLast100Wins"]),
|
||||
JockeyLast100StrikeRate = SafeConvert.ToSingle(row["JockeyLast100StrikeRate"]),
|
||||
TrainerLast100Wins = SafeConvert.ToSingle(row["TrainerLast100Wins"]),
|
||||
TrainerLast100StrikeRate = SafeConvert.ToSingle(row["TrainerLast100StrikeRate"]),
|
||||
BestFixedOdds = SafeConvert.ToSingle(row["BestFixedOdds"]),
|
||||
Rating1 = rating1,
|
||||
Rating2 = rating2,
|
||||
Rating3 = rating3,
|
||||
Rating4 = rating4,
|
||||
Rating5 = rating5
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
skippedRows++;
|
||||
}
|
||||
}
|
||||
Console.WriteLine($"[ML] Record letti dal database: {table.Rows.Count}");
|
||||
Console.WriteLine($"[ML] Record saltati: {skippedRows}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[ML][ERRORE] Errore durante il caricamento dei dati dal database: {ex.Message}");
|
||||
}
|
||||
|
||||
Console.WriteLine($"[ML] Caricati {trainingData.Count} record per l'addestramento.");
|
||||
return trainingData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Costruisce la pipeline di addestramento del modello
|
||||
/// </summary>
|
||||
private IEstimator<ITransformer> BuildTrainingPipeline()
|
||||
{
|
||||
// Crea la pipeline per addestramento
|
||||
// 1. Concatena tutte le feature in un unico vettore
|
||||
// 2. Normalizza i dati di input
|
||||
// 3. Addestra un modello FastTree con FastTreeRegressionTrainer
|
||||
var pipeline = _mlContext.Transforms.Concatenate("Features",
|
||||
"Age", "HandicapRating", "Weight", "WeightCarried", "Barrier",
|
||||
"CareerRuns", "CareerWins", "CareerStrikeRate", "CareerROI",
|
||||
"ThisTrackRuns", "ThisTrackWins", "ThisTrackStrikeRate",
|
||||
"ThisDistanceRuns", "ThisDistanceWins", "ThisDistanceStrikeRate",
|
||||
"JockeyLast100Wins", "JockeyLast100StrikeRate",
|
||||
"TrainerLast100Wins", "TrainerLast100StrikeRate", "BestFixedOdds",
|
||||
"Rating1", "Rating2", "Rating3", "Rating4", "Rating5")
|
||||
.Append(_mlContext.Transforms.NormalizeMinMax("Features"))
|
||||
.Append(_mlContext.Regression.Trainers.FastTree(
|
||||
labelColumnName: "FinishPosition",
|
||||
featureColumnName: "Features",
|
||||
numberOfTrees: 100,
|
||||
numberOfLeaves: 20,
|
||||
minimumExampleCountPerLeaf: 10));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Valuta il modello addestrato
|
||||
/// </summary>
|
||||
private RegressionMetrics EvaluateModel(IDataView dataView, ITransformer model)
|
||||
{
|
||||
var predictions = model.Transform(dataView);
|
||||
return _mlContext.Regression.Evaluate(predictions, labelColumnName: "FinishPosition");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Predice la posizione finale per un cavallo
|
||||
/// </summary>
|
||||
public ModelOutput PredictFinishPosition(ModelInput input)
|
||||
{
|
||||
if (_trainedModel == null)
|
||||
{
|
||||
Console.WriteLine("Il modello non è stato addestrato o caricato.");
|
||||
|
||||
// Restituisci un oggetto vuoto invece di lanciare un'eccezione
|
||||
return new ModelOutput
|
||||
{
|
||||
PredictedPosition = 0,
|
||||
WinProbability = 0,
|
||||
PlaceProbability = 0
|
||||
};
|
||||
}
|
||||
|
||||
// Crea il motore di previsione
|
||||
var predEngine = _mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(_trainedModel);
|
||||
|
||||
// Effettua la previsione
|
||||
var prediction = predEngine.Predict(input);
|
||||
|
||||
// Calcola le probabilità (implementazione semplificata)
|
||||
prediction.WinProbability = CalculateWinProbability(prediction.PredictedPosition);
|
||||
prediction.PlaceProbability = CalculatePlaceProbability(prediction.PredictedPosition);
|
||||
|
||||
return prediction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calcola la probabilità di vittoria in base alla posizione prevista
|
||||
/// </summary>
|
||||
private float CalculateWinProbability(float predictedPosition)
|
||||
{
|
||||
// Implementazione semplice: più il valore è vicino a 1, maggiore è la probabilità di vittoria
|
||||
if (predictedPosition <= 1) return 0.9f;
|
||||
if (predictedPosition <= 2) return 0.5f;
|
||||
if (predictedPosition <= 3) return 0.3f;
|
||||
if (predictedPosition <= 5) return 0.1f;
|
||||
return 0.05f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calcola la probabilità di piazzamento (primi 3) in base alla posizione prevista
|
||||
/// </summary>
|
||||
private float CalculatePlaceProbability(float predictedPosition)
|
||||
{
|
||||
// Implementazione semplice: più il valore è vicino a 1, 2 o 3, maggiore è la probabilità di piazzamento
|
||||
if (predictedPosition <= 1) return 0.95f;
|
||||
if (predictedPosition <= 2) return 0.85f;
|
||||
if (predictedPosition <= 3) return 0.75f;
|
||||
if (predictedPosition <= 4) return 0.4f;
|
||||
if (predictedPosition <= 6) return 0.2f;
|
||||
return 0.1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Analizza un'intera corsa e prevede il risultato per tutti i cavalli
|
||||
/// </summary>
|
||||
public List<HorseRacePrediction> PredictRaceResult(string meeting, int raceNumber, DateTime raceDate, string connectionString)
|
||||
{
|
||||
var predictions = new List<HorseRacePrediction>();
|
||||
var calculator = new HorseRacingPredictor.Horses.Calculator(); // Inizializza il calculator qui
|
||||
|
||||
try
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
connection.Open();
|
||||
string query = @"
|
||||
SELECT
|
||||
Num, HorseName,
|
||||
COALESCE(Age, 0) AS Age,
|
||||
COALESCE(HandicapRating, 0) AS HandicapRating,
|
||||
COALESCE(Weight, 0) AS Weight,
|
||||
COALESCE(WeightCarried, 0) AS WeightCarried,
|
||||
COALESCE(Barrier, 0) AS Barrier,
|
||||
COALESCE(CareerRuns, 0) AS CareerRuns,
|
||||
COALESCE(CareerWins, 0) AS CareerWins,
|
||||
COALESCE(CareerStrikeRate, 0) AS CareerStrikeRate,
|
||||
COALESCE(CareerROI, 0) AS CareerROI,
|
||||
COALESCE(ThisTrackRuns, 0) AS ThisTrackRuns,
|
||||
COALESCE(ThisTrackWins, 0) AS ThisTrackWins,
|
||||
COALESCE(ThisTrackStrikeRate, 0) AS ThisTrackStrikeRate,
|
||||
COALESCE(ThisDistanceRuns, 0) AS ThisDistanceRuns,
|
||||
COALESCE(ThisDistanceWins, 0) AS ThisDistanceWins,
|
||||
COALESCE(ThisDistanceStrikeRate, 0) AS ThisDistanceStrikeRate,
|
||||
COALESCE(JockeyLast100Wins, 0) AS JockeyLast100Wins,
|
||||
COALESCE(JockeyLast100StrikeRate, 0) AS JockeyLast100StrikeRate,
|
||||
COALESCE(TrainerLast100Wins, 0) AS TrainerLast100Wins,
|
||||
COALESCE(TrainerLast100StrikeRate, 0) AS TrainerLast100StrikeRate,
|
||||
COALESCE(BestFixedOdds, 0) AS BestFixedOdds,
|
||||
COALESCE(Gender, '') AS Gender
|
||||
FROM Races
|
||||
WHERE Meeting = @Meeting AND Race = @Race AND Data = @Data";
|
||||
|
||||
using (var command = new SqlCommand(query, connection))
|
||||
{
|
||||
command.Parameters.AddWithValue("@Meeting", meeting);
|
||||
command.Parameters.AddWithValue("@Race", raceNumber);
|
||||
command.Parameters.AddWithValue("@Data", raceDate);
|
||||
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
// Converti i dati del reader in una DataRow per usare il calculator
|
||||
DataTable dt = new DataTable();
|
||||
DataRow row = dt.NewRow();
|
||||
for (int i = 0; i < reader.FieldCount; i++)
|
||||
{
|
||||
if (!dt.Columns.Contains(reader.GetName(i)))
|
||||
dt.Columns.Add(reader.GetName(i));
|
||||
row[reader.GetName(i)] = reader.GetValue(i);
|
||||
}
|
||||
dt.Rows.Add(row);
|
||||
|
||||
// Prepara l'input per il modello
|
||||
var input = new ModelInput
|
||||
{
|
||||
Age = Convert.ToSingle(reader["Age"]),
|
||||
HandicapRating = Convert.ToSingle(reader["HandicapRating"]),
|
||||
Weight = Convert.ToSingle(reader["Weight"]),
|
||||
WeightCarried = Convert.ToSingle(reader["WeightCarried"]),
|
||||
Barrier = Convert.ToSingle(reader["Barrier"]),
|
||||
CareerRuns = Convert.ToSingle(reader["CareerRuns"]),
|
||||
CareerWins = Convert.ToSingle(reader["CareerWins"]),
|
||||
CareerStrikeRate = Convert.ToSingle(reader["CareerStrikeRate"]),
|
||||
CareerROI = Convert.ToSingle(reader["CareerROI"]),
|
||||
ThisTrackRuns = Convert.ToSingle(reader["ThisTrackRuns"]),
|
||||
ThisTrackWins = Convert.ToSingle(reader["ThisTrackWins"]),
|
||||
ThisTrackStrikeRate = Convert.ToSingle(reader["ThisTrackStrikeRate"]),
|
||||
ThisDistanceRuns = Convert.ToSingle(reader["ThisDistanceRuns"]),
|
||||
ThisDistanceWins = Convert.ToSingle(reader["ThisDistanceWins"]),
|
||||
ThisDistanceStrikeRate = Convert.ToSingle(reader["ThisDistanceStrikeRate"]),
|
||||
JockeyLast100Wins = Convert.ToSingle(reader["JockeyLast100Wins"]),
|
||||
JockeyLast100StrikeRate = Convert.ToSingle(reader["JockeyLast100StrikeRate"]),
|
||||
TrainerLast100Wins = Convert.ToSingle(reader["TrainerLast100Wins"]),
|
||||
TrainerLast100StrikeRate = Convert.ToSingle(reader["TrainerLast100StrikeRate"]),
|
||||
BestFixedOdds = Convert.ToSingle(reader["BestFixedOdds"]),
|
||||
// Aggiungi i rating calcolati
|
||||
Rating1 = (float)calculator.CalculateRating1(row),
|
||||
Rating2 = (float)calculator.CalculateRating2(row),
|
||||
Rating3 = (float)calculator.CalculateRating3(row),
|
||||
Rating4 = (float)calculator.CalculateRating4(row),
|
||||
Rating5 = (float)calculator.CalculateRating5(row)
|
||||
};
|
||||
|
||||
// Effettua la previsione
|
||||
var output = PredictFinishPosition(input);
|
||||
|
||||
// Calcola un rating ML basato sulla posizione prevista
|
||||
int mlRating = CalculateMLRating(output);
|
||||
|
||||
// Aggiungi alla lista delle previsioni
|
||||
predictions.Add(new HorseRacePrediction
|
||||
{
|
||||
HorseId = Convert.ToString(reader["Num"]),
|
||||
HorseName = Convert.ToString(reader["HorseName"]),
|
||||
RaceMeeting = meeting,
|
||||
RaceNumber = raceNumber,
|
||||
RaceDate = raceDate,
|
||||
PredictedPosition = output.PredictedPosition,
|
||||
WinProbability = output.WinProbability,
|
||||
PlaceProbability = output.PlaceProbability,
|
||||
MLRating = mlRating,
|
||||
CurrentOdds = Convert.ToSingle(reader["BestFixedOdds"])
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ordina per posizione prevista (dal migliore al peggiore)
|
||||
return predictions.OrderBy(p => p.PredictedPosition).ToList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[ML][ERRORE] Errore durante la previsione della corsa: {ex.Message}");
|
||||
return predictions;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calcola un rating ML basato sulla posizione prevista e altre metriche
|
||||
/// </summary>
|
||||
private int CalculateMLRating(ModelOutput output)
|
||||
{
|
||||
// Formula per il rating ML (convertito in un numero intero da 0 a 100)
|
||||
double baseRating = (1 / Math.Max(0.1, output.PredictedPosition)) * 100;
|
||||
double winProbabilityFactor = output.WinProbability * 100;
|
||||
double placeProbabilityFactor = output.PlaceProbability * 50;
|
||||
|
||||
// Combina i fattori con pesi diversi
|
||||
double combinedRating = (baseRating * 0.4) + (winProbabilityFactor * 0.4) + (placeProbabilityFactor * 0.2);
|
||||
|
||||
// Limita il valore tra 0 e 100
|
||||
return (int)Math.Min(100, Math.Max(0, combinedRating));
|
||||
}
|
||||
|
||||
// Metodo di utilità per convertire in modo sicuro i valori
|
||||
private static class SafeConvert
|
||||
{
|
||||
public static float ToSingle(object value, float defaultValue = 0)
|
||||
{
|
||||
if (value == null || value == DBNull.Value)
|
||||
return defaultValue;
|
||||
|
||||
try {
|
||||
float result = Convert.ToSingle(value);
|
||||
return float.IsNaN(result) || float.IsInfinity(result) ? defaultValue : result;
|
||||
}
|
||||
catch {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
using Microsoft.ML.Data;
|
||||
|
||||
namespace HorseRacingPredictor.Horses.ML
|
||||
{
|
||||
/// <summary>
|
||||
/// Classe che rappresenta i dati di input per l'addestramento del modello ML.
|
||||
/// Contiene le feature selezionate dalle corse passate.
|
||||
/// </summary>
|
||||
public class ModelInput
|
||||
{
|
||||
// Etichetta da prevedere: posizione finale (1 = vincitore, 2 = secondo posto, ecc.)
|
||||
[LoadColumn(0)]
|
||||
[ColumnName("FinishPosition")]
|
||||
public float FinishPosition { get; set; }
|
||||
|
||||
// Feature principali sul cavallo
|
||||
[LoadColumn(1)]
|
||||
[ColumnName("Age")]
|
||||
public float Age { get; set; }
|
||||
|
||||
[LoadColumn(2)]
|
||||
[ColumnName("HandicapRating")]
|
||||
public float HandicapRating { get; set; }
|
||||
|
||||
[LoadColumn(3)]
|
||||
[ColumnName("Weight")]
|
||||
public float Weight { get; set; }
|
||||
|
||||
[LoadColumn(4)]
|
||||
[ColumnName("WeightCarried")]
|
||||
public float WeightCarried { get; set; }
|
||||
|
||||
[LoadColumn(5)]
|
||||
[ColumnName("Barrier")]
|
||||
public float Barrier { get; set; }
|
||||
|
||||
// Statistiche di carriera
|
||||
[LoadColumn(6)]
|
||||
[ColumnName("CareerRuns")]
|
||||
public float CareerRuns { get; set; }
|
||||
|
||||
[LoadColumn(7)]
|
||||
[ColumnName("CareerWins")]
|
||||
public float CareerWins { get; set; }
|
||||
|
||||
[LoadColumn(8)]
|
||||
[ColumnName("CareerStrikeRate")]
|
||||
public float CareerStrikeRate { get; set; }
|
||||
|
||||
[LoadColumn(9)]
|
||||
[ColumnName("CareerROI")]
|
||||
public float CareerROI { get; set; }
|
||||
|
||||
// Statistiche di pista
|
||||
[LoadColumn(10)]
|
||||
[ColumnName("ThisTrackRuns")]
|
||||
public float ThisTrackRuns { get; set; }
|
||||
|
||||
[LoadColumn(11)]
|
||||
[ColumnName("ThisTrackWins")]
|
||||
public float ThisTrackWins { get; set; }
|
||||
|
||||
[LoadColumn(12)]
|
||||
[ColumnName("ThisTrackStrikeRate")]
|
||||
public float ThisTrackStrikeRate { get; set; }
|
||||
|
||||
[LoadColumn(13)]
|
||||
[ColumnName("ThisDistanceRuns")]
|
||||
public float ThisDistanceRuns { get; set; }
|
||||
|
||||
[LoadColumn(14)]
|
||||
[ColumnName("ThisDistanceWins")]
|
||||
public float ThisDistanceWins { get; set; }
|
||||
|
||||
[LoadColumn(15)]
|
||||
[ColumnName("ThisDistanceStrikeRate")]
|
||||
public float ThisDistanceStrikeRate { get; set; }
|
||||
|
||||
// Statistiche fantino
|
||||
[LoadColumn(16)]
|
||||
[ColumnName("JockeyLast100Wins")]
|
||||
public float JockeyLast100Wins { get; set; }
|
||||
|
||||
[LoadColumn(17)]
|
||||
[ColumnName("JockeyLast100StrikeRate")]
|
||||
public float JockeyLast100StrikeRate { get; set; }
|
||||
|
||||
// Statistiche allenatore
|
||||
[LoadColumn(18)]
|
||||
[ColumnName("TrainerLast100Wins")]
|
||||
public float TrainerLast100Wins { get; set; }
|
||||
|
||||
[LoadColumn(19)]
|
||||
[ColumnName("TrainerLast100StrikeRate")]
|
||||
public float TrainerLast100StrikeRate { get; set; }
|
||||
|
||||
// Quota iniziale (può essere predittiva)
|
||||
[LoadColumn(20)]
|
||||
[ColumnName("BestFixedOdds")]
|
||||
public float BestFixedOdds { get; set; }
|
||||
|
||||
// Cambia il tipo da int a float
|
||||
public float Rating1 { get; set; }
|
||||
public float Rating2 { get; set; }
|
||||
public float Rating3 { get; set; }
|
||||
public float Rating4 { get; set; }
|
||||
public float Rating5 { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using Microsoft.ML.Data;
|
||||
|
||||
namespace HorseRacingPredictor.Horses.ML
|
||||
{
|
||||
/// <summary>
|
||||
/// Classe che rappresenta l'output della previsione del modello ML.
|
||||
/// </summary>
|
||||
public class ModelOutput
|
||||
{
|
||||
// Previsione: il risultato della classificazione (1 = vincitore, 2 = secondo posto, ecc.)
|
||||
[ColumnName("Score")]
|
||||
public float PredictedPosition { get; set; }
|
||||
|
||||
[NoColumn] // Indica che questa proprietà non esiste nei dati
|
||||
public float WinProbability { get; set; }
|
||||
|
||||
[NoColumn] // Indica che questa proprietà non esiste nei dati
|
||||
public float PlaceProbability { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,360 +1,583 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using BettingPredictor.UI;
|
||||
|
||||
namespace BettingPredictor
|
||||
{
|
||||
partial class Main
|
||||
{
|
||||
// Container
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
// Grafica
|
||||
private TabControl tabControl;
|
||||
// Layout
|
||||
private Panel panelSidebar;
|
||||
private Panel panelContent;
|
||||
private Panel panelHeader;
|
||||
private Label labelAppTitle;
|
||||
private Label labelPageTitle;
|
||||
|
||||
// Horse tab
|
||||
private TabPage tabPageHorse;
|
||||
private TextBox textBoxFolderPath;
|
||||
private Button buttonBrowse;
|
||||
private Button buttonPredict; // New button for predictions
|
||||
private Button buttonImport; // New button for import
|
||||
private ProgressBar progressBarHorse;
|
||||
private Label labelStatusHorse;
|
||||
private DataGridView dataGridViewHorse;
|
||||
// Nav
|
||||
private NavButton navFootball;
|
||||
private NavButton navHorseRacing;
|
||||
private NavButton navSettings;
|
||||
private NavButton navInfo;
|
||||
|
||||
// Replace the buttonLoadFootball with buttonImportFootball and add buttonDownloadFootball
|
||||
// Football tab
|
||||
private TabPage tabPageFootball;
|
||||
// Pagine
|
||||
private Panel pageFootball;
|
||||
private Panel pageHorseRacing;
|
||||
private Panel pageSettings;
|
||||
private Panel pageInfo;
|
||||
|
||||
// Football
|
||||
private DateTimePicker dateTimePicker;
|
||||
private Button buttonImportFootball;
|
||||
private Button buttonDownloadFootball;
|
||||
private DataGridView dataGridViewFootball;
|
||||
private ProgressBar progressBarFootball;
|
||||
private ModernButton btnDownload;
|
||||
private ModernButton btnExportCsv;
|
||||
private ModernProgressBar progressBarFootball;
|
||||
private Label labelStatusFootball;
|
||||
private DataGridView dataGridViewFootball;
|
||||
|
||||
// ApiOptions class definition - rimosso GetLeagueData
|
||||
public static class ApiOptions
|
||||
{
|
||||
public const string GetLeagueFixtures = "Visualizza elenco partite alla data";
|
||||
public const string GetLeagueOdds = "Visualizza elenco quote partite";
|
||||
// Horse Racing
|
||||
private ComboBox cmbRacingDay;
|
||||
private ModernButton btnDownloadRacing;
|
||||
private ModernButton btnExportRacingCsv;
|
||||
private ModernProgressBar progressBarRacing;
|
||||
private Label labelStatusRacing;
|
||||
private DataGridView dataGridViewRacing;
|
||||
|
||||
public static readonly string[] AllOptions = { GetLeagueFixtures, GetLeagueOdds };
|
||||
}
|
||||
// Impostazioni
|
||||
private Label lblApiKey;
|
||||
private TextBox txtApiKey;
|
||||
private Label lblExportPath;
|
||||
private TextBox txtExportPath;
|
||||
private ModernButton btnBrowseExport;
|
||||
private Label lblRacingUser;
|
||||
private TextBox txtRacingUser;
|
||||
private Label lblRacingPass;
|
||||
private TextBox txtRacingPass;
|
||||
private ModernButton btnSaveSettings;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.tabControl = new System.Windows.Forms.TabControl();
|
||||
|
||||
// Horse Tab
|
||||
this.tabPageHorse = new System.Windows.Forms.TabPage();
|
||||
this.textBoxFolderPath = new System.Windows.Forms.TextBox();
|
||||
this.buttonBrowse = new System.Windows.Forms.Button();
|
||||
this.buttonPredict = new System.Windows.Forms.Button(); // New button for predictions
|
||||
this.buttonImport = new System.Windows.Forms.Button(); // New button for import
|
||||
this.progressBarHorse = new System.Windows.Forms.ProgressBar();
|
||||
this.labelStatusHorse = new System.Windows.Forms.Label();
|
||||
this.dataGridViewHorse = new System.Windows.Forms.DataGridView();
|
||||
|
||||
// In the InitializeComponent method, update:
|
||||
// Football Tab
|
||||
this.tabPageFootball = new System.Windows.Forms.TabPage();
|
||||
this.dateTimePicker = new System.Windows.Forms.DateTimePicker();
|
||||
this.buttonImportFootball = new System.Windows.Forms.Button();
|
||||
this.buttonDownloadFootball = new System.Windows.Forms.Button();
|
||||
this.progressBarFootball = new System.Windows.Forms.ProgressBar();
|
||||
this.labelStatusFootball = new System.Windows.Forms.Label();
|
||||
this.dataGridViewFootball = new System.Windows.Forms.DataGridView();
|
||||
|
||||
this.tabControl.SuspendLayout();
|
||||
this.tabPageHorse.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridViewHorse)).BeginInit();
|
||||
this.tabPageFootball.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridViewFootball)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
|
||||
//
|
||||
// tabControl
|
||||
//
|
||||
this.tabControl.Controls.Add(this.tabPageHorse);
|
||||
this.tabControl.Controls.Add(this.tabPageFootball);
|
||||
this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tabControl.Location = new System.Drawing.Point(0, 0);
|
||||
this.tabControl.Name = "tabControl";
|
||||
this.tabControl.SelectedIndex = 0;
|
||||
this.tabControl.Size = new System.Drawing.Size(800, 450);
|
||||
this.tabControl.TabIndex = 0;
|
||||
|
||||
//
|
||||
// tabPageHorse
|
||||
//
|
||||
this.tabPageHorse.Controls.Add(this.dataGridViewHorse);
|
||||
this.tabPageHorse.Controls.Add(this.labelStatusHorse);
|
||||
this.tabPageHorse.Controls.Add(this.progressBarHorse);
|
||||
this.tabPageHorse.Controls.Add(this.buttonPredict); // Add new button
|
||||
this.tabPageHorse.Controls.Add(this.buttonImport); // Add new button
|
||||
this.tabPageHorse.Controls.Add(this.buttonBrowse);
|
||||
this.tabPageHorse.Controls.Add(this.textBoxFolderPath);
|
||||
this.tabPageHorse.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPageHorse.Name = "tabPageHorse";
|
||||
this.tabPageHorse.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPageHorse.Size = new System.Drawing.Size(792, 424);
|
||||
this.tabPageHorse.TabIndex = 0;
|
||||
this.tabPageHorse.Text = "Horse";
|
||||
this.tabPageHorse.UseVisualStyleBackColor = true;
|
||||
|
||||
//
|
||||
// textBoxFolderPath
|
||||
//
|
||||
this.textBoxFolderPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.textBoxFolderPath.Location = new System.Drawing.Point(8, 8);
|
||||
this.textBoxFolderPath.Name = "textBoxFolderPath";
|
||||
this.textBoxFolderPath.ReadOnly = true;
|
||||
this.textBoxFolderPath.Size = new System.Drawing.Size(510, 20);
|
||||
this.textBoxFolderPath.TabIndex = 0;
|
||||
|
||||
//
|
||||
// buttonBrowse
|
||||
//
|
||||
this.buttonBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.buttonBrowse.Location = new System.Drawing.Point(524, 6); // Moved position to make room for Predict button
|
||||
this.buttonBrowse.Size = new System.Drawing.Size(80, 23);
|
||||
this.buttonBrowse.Name = "buttonBrowse";
|
||||
this.buttonBrowse.TabIndex = 1;
|
||||
this.buttonBrowse.Text = "Sfoglia...";
|
||||
this.buttonBrowse.UseVisualStyleBackColor = true;
|
||||
this.buttonBrowse.Click += new System.EventHandler(this.buttonBrowse_Click);
|
||||
|
||||
//
|
||||
// buttonImport
|
||||
//
|
||||
this.buttonImport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.buttonImport.Location = new System.Drawing.Point(610, 6);
|
||||
this.buttonImport.Name = "buttonImport";
|
||||
this.buttonImport.Size = new System.Drawing.Size(80, 23);
|
||||
this.buttonImport.TabIndex = 6;
|
||||
this.buttonImport.Text = "Importa";
|
||||
this.buttonImport.UseVisualStyleBackColor = true;
|
||||
this.buttonImport.Click += new System.EventHandler(this.buttonImport_Click);
|
||||
|
||||
//
|
||||
// buttonPredict
|
||||
//
|
||||
this.buttonPredict.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.buttonPredict.Location = new System.Drawing.Point(696, 6);
|
||||
this.buttonPredict.Name = "buttonPredict";
|
||||
this.buttonPredict.Size = new System.Drawing.Size(80, 23);
|
||||
this.buttonPredict.TabIndex = 5;
|
||||
this.buttonPredict.Text = "Predici";
|
||||
this.buttonPredict.UseVisualStyleBackColor = true;
|
||||
this.buttonPredict.Click += new System.EventHandler(this.buttonPredict_Click);
|
||||
|
||||
//
|
||||
// progressBarHorse
|
||||
//
|
||||
this.progressBarHorse.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.progressBarHorse.Location = new System.Drawing.Point(8, 34);
|
||||
this.progressBarHorse.Name = "progressBarHorse";
|
||||
this.progressBarHorse.Size = new System.Drawing.Size(762, 20);
|
||||
this.progressBarHorse.TabIndex = 2;
|
||||
|
||||
//
|
||||
// labelStatusHorse
|
||||
//
|
||||
this.labelStatusHorse.AutoSize = true;
|
||||
this.labelStatusHorse.Location = new System.Drawing.Point(8, 57);
|
||||
this.labelStatusHorse.Name = "labelStatusHorse";
|
||||
this.labelStatusHorse.Size = new System.Drawing.Size(38, 13);
|
||||
this.labelStatusHorse.TabIndex = 3;
|
||||
this.labelStatusHorse.Text = "Pronto";
|
||||
|
||||
//
|
||||
// dataGridViewHorse
|
||||
//
|
||||
this.dataGridViewHorse.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.dataGridViewHorse.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dataGridViewHorse.Location = new System.Drawing.Point(8, 73);
|
||||
this.dataGridViewHorse.Name = "dataGridViewHorse";
|
||||
this.dataGridViewHorse.ReadOnly = true;
|
||||
this.dataGridViewHorse.Size = new System.Drawing.Size(762, 343);
|
||||
this.dataGridViewHorse.TabIndex = 4;
|
||||
|
||||
// Update controls add to the tab page:
|
||||
this.tabPageFootball.Controls.Add(this.dataGridViewFootball);
|
||||
this.tabPageFootball.Controls.Add(this.labelStatusFootball);
|
||||
this.tabPageFootball.Controls.Add(this.progressBarFootball);
|
||||
this.tabPageFootball.Controls.Add(this.buttonImportFootball);
|
||||
this.tabPageFootball.Controls.Add(this.buttonDownloadFootball);
|
||||
this.tabPageFootball.Controls.Add(this.dateTimePicker);
|
||||
this.tabPageFootball.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPageFootball.Name = "tabPageFootball";
|
||||
this.tabPageFootball.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPageFootball.Size = new System.Drawing.Size(792, 424);
|
||||
this.tabPageFootball.TabIndex = 1;
|
||||
this.tabPageFootball.Text = "Football";
|
||||
this.tabPageFootball.UseVisualStyleBackColor = true;
|
||||
|
||||
//
|
||||
// dateTimePicker
|
||||
//
|
||||
this.dateTimePicker.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.dateTimePicker.Format = System.Windows.Forms.DateTimePickerFormat.Short;
|
||||
this.dateTimePicker.Location = new System.Drawing.Point(8, 8);
|
||||
this.dateTimePicker.Name = "dateTimePicker";
|
||||
// Update dateTimePicker size to make room for two buttons
|
||||
this.dateTimePicker.Size = new System.Drawing.Size(596, 20);
|
||||
this.dateTimePicker.TabIndex = 1;
|
||||
this.dateTimePicker.Value = System.DateTime.Today;
|
||||
|
||||
// buttonDownloadFootball properties
|
||||
this.buttonDownloadFootball.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.buttonDownloadFootball.Location = new System.Drawing.Point(610, 6);
|
||||
this.buttonDownloadFootball.Name = "buttonDownloadFootball";
|
||||
this.buttonDownloadFootball.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonDownloadFootball.TabIndex = 6;
|
||||
this.buttonDownloadFootball.Text = "Scarica";
|
||||
this.buttonDownloadFootball.UseVisualStyleBackColor = true;
|
||||
this.buttonDownloadFootball.Click += new System.EventHandler(this.buttonDownloadFootball_Click);
|
||||
|
||||
// buttonImportFootball properties (replace buttonLoadFootball)
|
||||
this.buttonImportFootball.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.buttonImportFootball.Location = new System.Drawing.Point(695, 6);
|
||||
this.buttonImportFootball.Name = "buttonImportFootball";
|
||||
this.buttonImportFootball.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonImportFootball.TabIndex = 2;
|
||||
this.buttonImportFootball.Text = "Importa";
|
||||
this.buttonImportFootball.UseVisualStyleBackColor = true;
|
||||
this.buttonImportFootball.Click += new System.EventHandler(this.buttonImportFootball_Click);
|
||||
|
||||
//
|
||||
// progressBarFootball
|
||||
//
|
||||
this.progressBarFootball.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.progressBarFootball.Location = new System.Drawing.Point(8, 35);
|
||||
this.progressBarFootball.Name = "progressBarFootball";
|
||||
this.progressBarFootball.Size = new System.Drawing.Size(762, 20);
|
||||
this.progressBarFootball.TabIndex = 3;
|
||||
|
||||
//
|
||||
// labelStatusFootball
|
||||
//
|
||||
this.labelStatusFootball.AutoSize = true;
|
||||
this.labelStatusFootball.Location = new System.Drawing.Point(8, 58);
|
||||
this.labelStatusFootball.Name = "labelStatusFootball";
|
||||
this.labelStatusFootball.Size = new System.Drawing.Size(38, 13);
|
||||
this.labelStatusFootball.TabIndex = 4;
|
||||
this.labelStatusFootball.Text = "Pronto";
|
||||
|
||||
//
|
||||
// dataGridViewFootball
|
||||
//
|
||||
this.dataGridViewFootball.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.dataGridViewFootball.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dataGridViewFootball.Location = new System.Drawing.Point(8, 74);
|
||||
this.dataGridViewFootball.Name = "dataGridViewFootball";
|
||||
this.dataGridViewFootball.ReadOnly = true;
|
||||
this.dataGridViewFootball.Size = new System.Drawing.Size(762, 342);
|
||||
this.dataGridViewFootball.TabIndex = 5;
|
||||
|
||||
//
|
||||
// Main
|
||||
//
|
||||
this.ClientSize = new System.Drawing.Size(800, 450);
|
||||
this.Controls.Add(this.tabControl);
|
||||
this.Name = "Main";
|
||||
// ============================================================
|
||||
// FORM
|
||||
// ============================================================
|
||||
this.ClientSize = new Size(1050, 620);
|
||||
this.MinimumSize = new Size(860, 520);
|
||||
this.Text = "Betting Predictor";
|
||||
this.Load += new System.EventHandler(this.Main_Load);
|
||||
this.tabControl.ResumeLayout(false);
|
||||
this.tabPageHorse.ResumeLayout(false);
|
||||
this.tabPageHorse.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridViewHorse)).EndInit();
|
||||
this.tabPageFootball.ResumeLayout(false);
|
||||
this.tabPageFootball.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridViewFootball)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
}
|
||||
}
|
||||
this.Name = "Main";
|
||||
this.StartPosition = FormStartPosition.CenterScreen;
|
||||
this.BackColor = ModernTheme.ContentBackground;
|
||||
this.ForeColor = ModernTheme.TextPrimary;
|
||||
this.Font = ModernTheme.BodyFont;
|
||||
this.DoubleBuffered = true;
|
||||
this.Load += new EventHandler(this.Main_Load);
|
||||
this.Resize += new EventHandler(this.Main_Resize);
|
||||
|
||||
public partial class ProgressDialog : Form
|
||||
{
|
||||
public ProgressDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void UpdateProgress(int currentPage, int totalPages)
|
||||
{
|
||||
progressBar.Maximum = totalPages;
|
||||
progressBar.Value = currentPage;
|
||||
labelProgress.Text = $"Scaricamento pagina {currentPage} di {totalPages}";
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
// ============================================================
|
||||
// SIDEBAR (Dock=Left, larghezza fissa)
|
||||
// ============================================================
|
||||
this.panelSidebar = new Panel
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
Dock = DockStyle.Left,
|
||||
Width = ModernTheme.SidebarWidth,
|
||||
BackColor = ModernTheme.SidebarBackground
|
||||
};
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.progressBar = new System.Windows.Forms.ProgressBar();
|
||||
this.labelProgress = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// progressBar
|
||||
//
|
||||
this.progressBar.Location = new System.Drawing.Point(12, 12);
|
||||
this.progressBar.Name = "progressBar";
|
||||
this.progressBar.Size = new System.Drawing.Size(360, 23);
|
||||
this.progressBar.TabIndex = 0;
|
||||
//
|
||||
// labelProgress
|
||||
//
|
||||
this.labelProgress.AutoSize = true;
|
||||
this.labelProgress.Location = new System.Drawing.Point(12, 38);
|
||||
this.labelProgress.Name = "labelProgress";
|
||||
this.labelProgress.Size = new System.Drawing.Size(0, 13);
|
||||
this.labelProgress.TabIndex = 1;
|
||||
//
|
||||
// ProgressDialog
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(384, 61);
|
||||
this.Controls.Add(this.labelProgress);
|
||||
this.Controls.Add(this.progressBar);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "ProgressDialog";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Scaricamento in corso...";
|
||||
this.labelAppTitle = new Label
|
||||
{
|
||||
Text = "Betting\nPredictor",
|
||||
Font = new Font("Segoe UI", 15F, FontStyle.Bold),
|
||||
ForeColor = ModernTheme.PrimaryColor,
|
||||
BackColor = ModernTheme.SidebarBackground,
|
||||
Dock = DockStyle.Top,
|
||||
Height = 72,
|
||||
TextAlign = ContentAlignment.MiddleCenter
|
||||
};
|
||||
|
||||
var sep = new Panel
|
||||
{
|
||||
Dock = DockStyle.Top,
|
||||
Height = 1,
|
||||
BackColor = ModernTheme.CardBorder
|
||||
};
|
||||
|
||||
// Nav — ordine di aggiunta inverso rispetto a quello visivo (Dock=Top)
|
||||
this.navInfo = new NavButton("Info", "i");
|
||||
this.navInfo.Click += new EventHandler(this.navInfo_Click);
|
||||
|
||||
this.navSettings = new NavButton("Impostazioni", "#");
|
||||
this.navSettings.Click += new EventHandler(this.navSettings_Click);
|
||||
|
||||
this.navHorseRacing = new NavButton("Corse Cavalli", "H");
|
||||
this.navHorseRacing.Click += new EventHandler(this.navHorseRacing_Click);
|
||||
|
||||
this.navFootball = new NavButton("Calcio", "F");
|
||||
this.navFootball.IsActive = true;
|
||||
this.navFootball.Click += new EventHandler(this.navFootball_Click);
|
||||
|
||||
this.panelSidebar.Controls.Add(this.navInfo);
|
||||
this.panelSidebar.Controls.Add(this.navSettings);
|
||||
this.panelSidebar.Controls.Add(this.navHorseRacing);
|
||||
this.panelSidebar.Controls.Add(this.navFootball);
|
||||
this.panelSidebar.Controls.Add(sep);
|
||||
this.panelSidebar.Controls.Add(this.labelAppTitle);
|
||||
|
||||
// ============================================================
|
||||
// HEADER (Dock=Top dentro panelContent)
|
||||
// ============================================================
|
||||
this.panelHeader = new Panel
|
||||
{
|
||||
Dock = DockStyle.Top,
|
||||
Height = 56,
|
||||
BackColor = ModernTheme.HeaderBackground,
|
||||
Padding = new Padding(24, 0, 24, 0)
|
||||
};
|
||||
|
||||
this.labelPageTitle = new Label
|
||||
{
|
||||
Text = "Calcio",
|
||||
Font = ModernTheme.TitleFont,
|
||||
ForeColor = ModernTheme.TextPrimary,
|
||||
BackColor = ModernTheme.HeaderBackground,
|
||||
Dock = DockStyle.Fill,
|
||||
TextAlign = ContentAlignment.MiddleLeft
|
||||
};
|
||||
this.panelHeader.Controls.Add(this.labelPageTitle);
|
||||
|
||||
var headerLine = new Panel
|
||||
{
|
||||
Dock = DockStyle.Bottom,
|
||||
Height = 1,
|
||||
BackColor = ModernTheme.CardBorder
|
||||
};
|
||||
this.panelHeader.Controls.Add(headerLine);
|
||||
|
||||
// ============================================================
|
||||
// CONTENT WRAPPER (Dock=Fill, contiene header + pagine)
|
||||
// ============================================================
|
||||
this.panelContent = new Panel
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
BackColor = ModernTheme.ContentBackground
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// PAGE: CALCIO
|
||||
// ============================================================
|
||||
this.pageFootball = new Panel
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
Padding = new Padding(24, 16, 24, 16),
|
||||
BackColor = ModernTheme.ContentBackground,
|
||||
Visible = true
|
||||
};
|
||||
|
||||
// -- toolbar (altezza fissa, posizionamento manuale) --
|
||||
var toolbarFb = new Panel
|
||||
{
|
||||
Dock = DockStyle.Top,
|
||||
Height = 48,
|
||||
BackColor = ModernTheme.ContentBackground
|
||||
};
|
||||
|
||||
this.dateTimePicker = new DateTimePicker
|
||||
{
|
||||
Format = DateTimePickerFormat.Short,
|
||||
Value = DateTime.Today,
|
||||
Font = ModernTheme.BodyFont,
|
||||
CalendarMonthBackground = ModernTheme.InputBackground,
|
||||
CalendarForeColor = ModernTheme.InputText
|
||||
};
|
||||
|
||||
this.btnDownload = new ModernButton { Text = "Scarica Partite", Size = new Size(140, 34) };
|
||||
this.btnDownload.Click += new EventHandler(this.btnDownload_Click);
|
||||
|
||||
this.btnExportCsv = new ModernButton
|
||||
{
|
||||
Text = "Esporta CSV",
|
||||
AccentColor = ModernTheme.SuccessColor,
|
||||
Size = new Size(120, 34),
|
||||
Enabled = false
|
||||
};
|
||||
this.btnExportCsv.Click += new EventHandler(this.btnExportCsv_Click);
|
||||
|
||||
toolbarFb.Controls.Add(this.dateTimePicker);
|
||||
toolbarFb.Controls.Add(this.btnDownload);
|
||||
toolbarFb.Controls.Add(this.btnExportCsv);
|
||||
|
||||
// -- status --
|
||||
var statusFb = new Panel
|
||||
{
|
||||
Dock = DockStyle.Top,
|
||||
Height = 30,
|
||||
BackColor = ModernTheme.ContentBackground
|
||||
};
|
||||
|
||||
this.progressBarFootball = new ModernProgressBar { Dock = DockStyle.Top };
|
||||
|
||||
this.labelStatusFootball = new Label
|
||||
{
|
||||
Text = "Pronto",
|
||||
Font = ModernTheme.SmallFont,
|
||||
ForeColor = ModernTheme.TextSecondary,
|
||||
BackColor = ModernTheme.ContentBackground,
|
||||
Dock = DockStyle.Fill,
|
||||
TextAlign = ContentAlignment.MiddleLeft
|
||||
};
|
||||
statusFb.Controls.Add(this.labelStatusFootball);
|
||||
statusFb.Controls.Add(this.progressBarFootball);
|
||||
|
||||
// -- grid --
|
||||
this.dataGridViewFootball = new DataGridView { Dock = DockStyle.Fill };
|
||||
((System.ComponentModel.ISupportInitialize)this.dataGridViewFootball).BeginInit();
|
||||
ModernTheme.StyleDataGridView(this.dataGridViewFootball);
|
||||
|
||||
this.pageFootball.Controls.Add(this.dataGridViewFootball);
|
||||
this.pageFootball.Controls.Add(statusFb);
|
||||
this.pageFootball.Controls.Add(toolbarFb);
|
||||
|
||||
// ============================================================
|
||||
// PAGE: CORSE CAVALLI
|
||||
// ============================================================
|
||||
this.pageHorseRacing = new Panel
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
Padding = new Padding(24, 16, 24, 16),
|
||||
BackColor = ModernTheme.ContentBackground,
|
||||
Visible = false
|
||||
};
|
||||
|
||||
// -- toolbar racing --
|
||||
var toolbarRacing = new Panel
|
||||
{
|
||||
Dock = DockStyle.Top,
|
||||
Height = 48,
|
||||
BackColor = ModernTheme.ContentBackground,
|
||||
Name = "toolbarRacing"
|
||||
};
|
||||
|
||||
this.cmbRacingDay = new ComboBox
|
||||
{
|
||||
DropDownStyle = ComboBoxStyle.DropDownList,
|
||||
Font = ModernTheme.BodyFont,
|
||||
BackColor = ModernTheme.InputBackground,
|
||||
ForeColor = ModernTheme.InputText,
|
||||
FlatStyle = FlatStyle.Flat,
|
||||
Size = new Size(160, 28)
|
||||
};
|
||||
this.cmbRacingDay.Items.AddRange(new object[] { "Oggi", "Domani" });
|
||||
this.cmbRacingDay.SelectedIndex = 0;
|
||||
|
||||
this.btnDownloadRacing = new ModernButton { Text = "Scarica Corse", Size = new Size(140, 34) };
|
||||
this.btnDownloadRacing.Click += new EventHandler(this.btnDownloadRacing_Click);
|
||||
|
||||
this.btnExportRacingCsv = new ModernButton
|
||||
{
|
||||
Text = "Esporta CSV",
|
||||
AccentColor = ModernTheme.SuccessColor,
|
||||
Size = new Size(120, 34),
|
||||
Enabled = false
|
||||
};
|
||||
this.btnExportRacingCsv.Click += new EventHandler(this.btnExportRacingCsv_Click);
|
||||
|
||||
toolbarRacing.Controls.Add(this.cmbRacingDay);
|
||||
toolbarRacing.Controls.Add(this.btnDownloadRacing);
|
||||
toolbarRacing.Controls.Add(this.btnExportRacingCsv);
|
||||
|
||||
// -- status racing --
|
||||
var statusRacing = new Panel
|
||||
{
|
||||
Dock = DockStyle.Top,
|
||||
Height = 30,
|
||||
BackColor = ModernTheme.ContentBackground
|
||||
};
|
||||
|
||||
this.progressBarRacing = new ModernProgressBar { Dock = DockStyle.Top };
|
||||
|
||||
this.labelStatusRacing = new Label
|
||||
{
|
||||
Text = "Pronto",
|
||||
Font = ModernTheme.SmallFont,
|
||||
ForeColor = ModernTheme.TextSecondary,
|
||||
BackColor = ModernTheme.ContentBackground,
|
||||
Dock = DockStyle.Fill,
|
||||
TextAlign = ContentAlignment.MiddleLeft
|
||||
};
|
||||
statusRacing.Controls.Add(this.labelStatusRacing);
|
||||
statusRacing.Controls.Add(this.progressBarRacing);
|
||||
|
||||
// -- grid racing --
|
||||
this.dataGridViewRacing = new DataGridView { Dock = DockStyle.Fill };
|
||||
((System.ComponentModel.ISupportInitialize)this.dataGridViewRacing).BeginInit();
|
||||
ModernTheme.StyleDataGridView(this.dataGridViewRacing);
|
||||
|
||||
this.pageHorseRacing.Controls.Add(this.dataGridViewRacing);
|
||||
this.pageHorseRacing.Controls.Add(statusRacing);
|
||||
this.pageHorseRacing.Controls.Add(toolbarRacing);
|
||||
|
||||
// ============================================================
|
||||
// PAGE: IMPOSTAZIONI
|
||||
// ============================================================
|
||||
this.pageSettings = new Panel
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
Padding = new Padding(24, 16, 24, 16),
|
||||
BackColor = ModernTheme.ContentBackground,
|
||||
Visible = false
|
||||
};
|
||||
|
||||
var settingsInner = new Panel
|
||||
{
|
||||
Dock = DockStyle.Top,
|
||||
Height = 400,
|
||||
BackColor = ModernTheme.CardBackground,
|
||||
Padding = new Padding(24)
|
||||
};
|
||||
|
||||
this.lblApiKey = new Label
|
||||
{
|
||||
Text = "API Key (api-football)",
|
||||
Font = ModernTheme.SubtitleFont,
|
||||
ForeColor = ModernTheme.TextPrimary,
|
||||
BackColor = ModernTheme.CardBackground,
|
||||
AutoSize = true,
|
||||
Location = new Point(24, 24)
|
||||
};
|
||||
|
||||
this.txtApiKey = new TextBox
|
||||
{
|
||||
Font = ModernTheme.BodyFont,
|
||||
BackColor = ModernTheme.InputBackground,
|
||||
ForeColor = ModernTheme.InputText,
|
||||
BorderStyle = BorderStyle.FixedSingle,
|
||||
Location = new Point(24, 52),
|
||||
Size = new Size(500, 28)
|
||||
};
|
||||
|
||||
this.lblExportPath = new Label
|
||||
{
|
||||
Text = "Cartella esportazione CSV",
|
||||
Font = ModernTheme.SubtitleFont,
|
||||
ForeColor = ModernTheme.TextPrimary,
|
||||
BackColor = ModernTheme.CardBackground,
|
||||
AutoSize = true,
|
||||
Location = new Point(24, 100)
|
||||
};
|
||||
|
||||
this.txtExportPath = new TextBox
|
||||
{
|
||||
Font = ModernTheme.BodyFont,
|
||||
BackColor = ModernTheme.InputBackground,
|
||||
ForeColor = ModernTheme.InputText,
|
||||
BorderStyle = BorderStyle.FixedSingle,
|
||||
ReadOnly = true,
|
||||
Location = new Point(24, 128),
|
||||
Size = new Size(400, 28)
|
||||
};
|
||||
|
||||
this.btnBrowseExport = new ModernButton
|
||||
{
|
||||
Text = "Sfoglia...",
|
||||
IsPrimary = false,
|
||||
Size = new Size(90, 30),
|
||||
Location = new Point(434, 126)
|
||||
};
|
||||
this.btnBrowseExport.Click += new EventHandler(this.btnBrowseExport_Click);
|
||||
|
||||
// Racing API credentials
|
||||
this.lblRacingUser = new Label
|
||||
{
|
||||
Text = "Racing API — Username",
|
||||
Font = ModernTheme.SubtitleFont,
|
||||
ForeColor = ModernTheme.TextPrimary,
|
||||
BackColor = ModernTheme.CardBackground,
|
||||
AutoSize = true,
|
||||
Location = new Point(24, 176)
|
||||
};
|
||||
|
||||
this.txtRacingUser = new TextBox
|
||||
{
|
||||
Font = ModernTheme.BodyFont,
|
||||
BackColor = ModernTheme.InputBackground,
|
||||
ForeColor = ModernTheme.InputText,
|
||||
BorderStyle = BorderStyle.FixedSingle,
|
||||
Location = new Point(24, 204),
|
||||
Size = new Size(500, 28)
|
||||
};
|
||||
|
||||
this.lblRacingPass = new Label
|
||||
{
|
||||
Text = "Racing API — Password",
|
||||
Font = ModernTheme.SubtitleFont,
|
||||
ForeColor = ModernTheme.TextPrimary,
|
||||
BackColor = ModernTheme.CardBackground,
|
||||
AutoSize = true,
|
||||
Location = new Point(24, 248)
|
||||
};
|
||||
|
||||
this.txtRacingPass = new TextBox
|
||||
{
|
||||
Font = ModernTheme.BodyFont,
|
||||
BackColor = ModernTheme.InputBackground,
|
||||
ForeColor = ModernTheme.InputText,
|
||||
BorderStyle = BorderStyle.FixedSingle,
|
||||
UseSystemPasswordChar = true,
|
||||
Location = new Point(24, 276),
|
||||
Size = new Size(500, 28)
|
||||
};
|
||||
|
||||
this.btnSaveSettings = new ModernButton
|
||||
{
|
||||
Text = "Salva impostazioni",
|
||||
AccentColor = ModernTheme.SuccessColor,
|
||||
Size = new Size(170, 36),
|
||||
Location = new Point(24, 330)
|
||||
};
|
||||
this.btnSaveSettings.Click += new EventHandler(this.btnSaveSettings_Click);
|
||||
|
||||
settingsInner.Controls.Add(this.btnSaveSettings);
|
||||
settingsInner.Controls.Add(this.txtRacingPass);
|
||||
settingsInner.Controls.Add(this.lblRacingPass);
|
||||
settingsInner.Controls.Add(this.txtRacingUser);
|
||||
settingsInner.Controls.Add(this.lblRacingUser);
|
||||
settingsInner.Controls.Add(this.btnBrowseExport);
|
||||
settingsInner.Controls.Add(this.txtExportPath);
|
||||
settingsInner.Controls.Add(this.lblExportPath);
|
||||
settingsInner.Controls.Add(this.txtApiKey);
|
||||
settingsInner.Controls.Add(this.lblApiKey);
|
||||
|
||||
this.pageSettings.Controls.Add(settingsInner);
|
||||
|
||||
// ============================================================
|
||||
// PAGE: INFO
|
||||
// ============================================================
|
||||
this.pageInfo = new Panel
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
Padding = new Padding(24, 16, 24, 16),
|
||||
BackColor = ModernTheme.ContentBackground,
|
||||
Visible = false
|
||||
};
|
||||
|
||||
var infoInner = new Panel
|
||||
{
|
||||
Dock = DockStyle.Top,
|
||||
Height = 280,
|
||||
BackColor = ModernTheme.CardBackground,
|
||||
Padding = new Padding(32)
|
||||
};
|
||||
|
||||
int infoY = 32;
|
||||
|
||||
var lblInfoTitle = new Label
|
||||
{
|
||||
Text = "Betting Predictor",
|
||||
Font = new Font("Segoe UI", 20F, FontStyle.Bold),
|
||||
ForeColor = ModernTheme.PrimaryColor,
|
||||
BackColor = ModernTheme.CardBackground,
|
||||
AutoSize = true,
|
||||
Location = new Point(32, infoY)
|
||||
};
|
||||
infoY += 48;
|
||||
|
||||
var lblVersion = new Label
|
||||
{
|
||||
Text = "Versione 1.0.0",
|
||||
Font = ModernTheme.SubtitleFont,
|
||||
ForeColor = ModernTheme.TextSecondary,
|
||||
BackColor = ModernTheme.CardBackground,
|
||||
AutoSize = true,
|
||||
Location = new Point(32, infoY)
|
||||
};
|
||||
infoY += 36;
|
||||
|
||||
var lblDesc = new Label
|
||||
{
|
||||
Text = "Applicazione per lo scaricamento e l'analisi di dati sportivi\n" +
|
||||
"tramite API esterne. Supporta l'esportazione in CSV.\n\n" +
|
||||
"Sviluppato con .NET Framework 4.8.1 | WinForms",
|
||||
Font = ModernTheme.BodyFont,
|
||||
ForeColor = ModernTheme.TextPrimary,
|
||||
BackColor = ModernTheme.CardBackground,
|
||||
AutoSize = true,
|
||||
Location = new Point(32, infoY)
|
||||
};
|
||||
infoY += 90;
|
||||
|
||||
var lblCopy = new Label
|
||||
{
|
||||
Text = $"© {DateTime.Now.Year} — Tutti i diritti riservati",
|
||||
Font = ModernTheme.SmallFont,
|
||||
ForeColor = ModernTheme.TextSecondary,
|
||||
BackColor = ModernTheme.CardBackground,
|
||||
AutoSize = true,
|
||||
Location = new Point(32, infoY)
|
||||
};
|
||||
|
||||
infoInner.Controls.Add(lblCopy);
|
||||
infoInner.Controls.Add(lblDesc);
|
||||
infoInner.Controls.Add(lblVersion);
|
||||
infoInner.Controls.Add(lblInfoTitle);
|
||||
|
||||
this.pageInfo.Controls.Add(infoInner);
|
||||
|
||||
// ============================================================
|
||||
// ASSEMBLY
|
||||
// ============================================================
|
||||
// Le pagine vanno aggiunte PRIMA dell'header nel panelContent
|
||||
// perché con Dock=Fill devono occupare lo spazio rimanente.
|
||||
this.panelContent.Controls.Add(this.pageFootball);
|
||||
this.panelContent.Controls.Add(this.pageHorseRacing);
|
||||
this.panelContent.Controls.Add(this.pageSettings);
|
||||
this.panelContent.Controls.Add(this.pageInfo);
|
||||
this.panelContent.Controls.Add(this.panelHeader);
|
||||
|
||||
this.Controls.Add(this.panelContent);
|
||||
this.Controls.Add(this.panelSidebar);
|
||||
|
||||
((System.ComponentModel.ISupportInitialize)this.dataGridViewFootball).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)this.dataGridViewRacing).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
private ProgressBar progressBar;
|
||||
private Label labelProgress;
|
||||
/// <summary>
|
||||
/// Posiziona manualmente i controlli nelle toolbar
|
||||
/// </summary>
|
||||
private void LayoutToolbars()
|
||||
{
|
||||
// Football toolbar
|
||||
if (dateTimePicker != null && dateTimePicker.Parent != null)
|
||||
{
|
||||
var tb = dateTimePicker.Parent;
|
||||
int w = tb.ClientSize.Width;
|
||||
int y = 7;
|
||||
|
||||
dateTimePicker.SetBounds(0, y, 200, 28);
|
||||
btnExportCsv.Location = new Point(w - btnExportCsv.Width, y);
|
||||
btnDownload.Location = new Point(btnExportCsv.Left - btnDownload.Width - 10, y);
|
||||
}
|
||||
|
||||
// Horse Racing toolbar
|
||||
if (cmbRacingDay != null && cmbRacingDay.Parent != null)
|
||||
{
|
||||
var tb = cmbRacingDay.Parent;
|
||||
int w = tb.ClientSize.Width;
|
||||
int y = 7;
|
||||
|
||||
cmbRacingDay.SetBounds(0, y, 160, 28);
|
||||
btnExportRacingCsv.Location = new Point(w - btnExportRacingCsv.Width, y);
|
||||
btnDownloadRacing.Location = new Point(btnExportRacingCsv.Left - btnDownloadRacing.Width - 10, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
664
HorseRacingPredictor/HorseRacingPredictor/MainWindow.xaml
Normal file
664
HorseRacingPredictor/HorseRacingPredictor/MainWindow.xaml
Normal file
@@ -0,0 +1,664 @@
|
||||
<Window x:Class="HorseRacingPredictor.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
|
||||
Title="Betting Predictor" Width="1100" Height="680"
|
||||
MinWidth="900" MinHeight="540"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="#1E1E2E"
|
||||
Loaded="Window_Loaded">
|
||||
|
||||
<Window.Resources>
|
||||
<!-- Inlined Global Styles (avoids relying on external resource resolution at runtime) -->
|
||||
<!-- CATPPUCCIN MOCHA PALETTE (shared) -->
|
||||
<Color x:Key="CBase">#1E1E2E</Color>
|
||||
<Color x:Key="CMantle">#181825</Color>
|
||||
<Color x:Key="CCrust">#11111B</Color>
|
||||
<Color x:Key="CSurface0">#313244</Color>
|
||||
<Color x:Key="CSurface1">#45475A</Color>
|
||||
<Color x:Key="CSurface2">#585B70</Color>
|
||||
<Color x:Key="COverlay0">#6C7086</Color>
|
||||
<Color x:Key="CText">#CDD6F4</Color>
|
||||
<Color x:Key="CSubtext0">#A6ADC8</Color>
|
||||
<Color x:Key="CSubtext1">#BAC2DE</Color>
|
||||
<Color x:Key="CBlue">#89B4FA</Color>
|
||||
<Color x:Key="CGreen">#A6E3A1</Color>
|
||||
<Color x:Key="CRed">#F38BA8</Color>
|
||||
<Color x:Key="CPeach">#FAB387</Color>
|
||||
<Color x:Key="CLavender">#B4BEFE</Color>
|
||||
|
||||
<SolidColorBrush x:Key="BrBase" Color="{StaticResource CBase}"/>
|
||||
<SolidColorBrush x:Key="BrMantle" Color="{StaticResource CMantle}"/>
|
||||
<SolidColorBrush x:Key="BrSurface0" Color="{StaticResource CSurface0}"/>
|
||||
<SolidColorBrush x:Key="BrSurface1" Color="{StaticResource CSurface1}"/>
|
||||
<SolidColorBrush x:Key="BrSurface2" Color="{StaticResource CSurface2}"/>
|
||||
<SolidColorBrush x:Key="BrOverlay0" Color="{StaticResource COverlay0}"/>
|
||||
<SolidColorBrush x:Key="BrText" Color="{StaticResource CText}"/>
|
||||
<SolidColorBrush x:Key="BrSubtext0" Color="{StaticResource CSubtext0}"/>
|
||||
<SolidColorBrush x:Key="BrBlue" Color="{StaticResource CBlue}"/>
|
||||
<SolidColorBrush x:Key="BrGreen" Color="{StaticResource CGreen}"/>
|
||||
<SolidColorBrush x:Key="BrRed" Color="{StaticResource CRed}"/>
|
||||
<SolidColorBrush x:Key="BrPeach" Color="{StaticResource CPeach}"/>
|
||||
<SolidColorBrush x:Key="BrLavender" Color="{StaticResource CLavender}"/>
|
||||
|
||||
<!-- Force ComboBox text to black for readability on light backgrounds -->
|
||||
<Style TargetType="ComboBox">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
</Style>
|
||||
<Style TargetType="ComboBoxItem">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
</Style>
|
||||
|
||||
<!-- Acrylic-like background (semi-transparent fallback) -->
|
||||
<SolidColorBrush x:Key="AcrylicBackgroundBrush" Color="#0F000000"/>
|
||||
|
||||
<!-- Subtle shadow effect for elevation -->
|
||||
<DropShadowEffect x:Key="SubtleDropShadow" BlurRadius="12" ShadowDepth="2" Color="#50000000"/>
|
||||
|
||||
<!-- NAV BUTTON STYLE (icon-only sidebar) -->
|
||||
<Style x:Key="NavBtn" TargetType="RadioButton">
|
||||
<Setter Property="Width" Value="48"/>
|
||||
<Setter Property="Height" Value="48"/>
|
||||
<Setter Property="Margin" Value="6,4"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrSubtext0}"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="RadioButton">
|
||||
<Grid>
|
||||
<Border x:Name="Bg" CornerRadius="10" Background="{TemplateBinding Background}"/>
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="Bg" Property="Background" Value="#28283A"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter TargetName="Bg" Property="Background" Value="{StaticResource BrBlue}"/>
|
||||
<Setter Property="Foreground" Value="#181825"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- ACCENT BUTTON -->
|
||||
<Style x:Key="AccentBtn" TargetType="Button">
|
||||
<Setter Property="Foreground" Value="#181825"/>
|
||||
<Setter Property="FontFamily" Value="Segoe UI Semibold"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="Padding" Value="18,7"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="Bd" CornerRadius="8"
|
||||
Background="{TemplateBinding Background}"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="Bd" Property="Opacity" Value="0.85"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="Bd" Property="Opacity" Value="0.40"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- FLAT TEXTBOX -->
|
||||
<Style x:Key="FlatTb" TargetType="TextBox">
|
||||
<Setter Property="Background" Value="{StaticResource BrSurface0}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrText}"/>
|
||||
<Setter Property="CaretBrush" Value="{StaticResource BrText}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource BrSurface1}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="10,7"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="FontFamily" Value="Segoe UI"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="TextBox">
|
||||
<Border x:Name="Bd" CornerRadius="6"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ScrollViewer x:Name="PART_ContentHost"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsFocused" Value="True">
|
||||
<Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource BrBlue}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- PASSWORD BOX -->
|
||||
<Style x:Key="FlatPb" TargetType="PasswordBox">
|
||||
<Setter Property="Background" Value="{StaticResource BrSurface0}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrText}"/>
|
||||
<Setter Property="CaretBrush" Value="{StaticResource BrText}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource BrSurface1}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="10,7"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="FontFamily" Value="Segoe UI"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="PasswordBox">
|
||||
<Border x:Name="Bd" CornerRadius="6"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ScrollViewer x:Name="PART_ContentHost"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsFocused" Value="True">
|
||||
<Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource BrBlue}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- PROGRESS BAR -->
|
||||
<Style x:Key="ModernPb" TargetType="ProgressBar">
|
||||
<Setter Property="Height" Value="4"/>
|
||||
<Setter Property="Background" Value="{StaticResource BrSurface0}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrBlue}"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ProgressBar">
|
||||
<Grid>
|
||||
<Border CornerRadius="2" Background="{TemplateBinding Background}"/>
|
||||
<Border x:Name="PART_Indicator" CornerRadius="2"
|
||||
Background="{TemplateBinding Foreground}"
|
||||
HorizontalAlignment="Left"/>
|
||||
<Border x:Name="PART_Track"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- DATAGRID -->
|
||||
<Style x:Key="ModernDg" TargetType="DataGrid">
|
||||
<Setter Property="Background" Value="#282A3A"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrText}"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="RowBackground" Value="#282A3A"/>
|
||||
<Setter Property="AlternatingRowBackground" Value="#2D2F42"/>
|
||||
<Setter Property="GridLinesVisibility" Value="Horizontal"/>
|
||||
<Setter Property="HorizontalGridLinesBrush" Value="#37394E"/>
|
||||
<Setter Property="HeadersVisibility" Value="Column"/>
|
||||
<Setter Property="RowHeaderWidth" Value="0"/>
|
||||
<Setter Property="AutoGenerateColumns" Value="True"/>
|
||||
<Setter Property="IsReadOnly" Value="True"/>
|
||||
<Setter Property="SelectionMode" Value="Single"/>
|
||||
<Setter Property="CanUserAddRows" Value="False"/>
|
||||
<Setter Property="CanUserDeleteRows" Value="False"/>
|
||||
<Setter Property="CanUserResizeRows" Value="False"/>
|
||||
<Setter Property="FontFamily" Value="Segoe UI"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="DataGridColumnHeader">
|
||||
<Setter Property="Background" Value="#23243A"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrBlue}"/>
|
||||
<Setter Property="FontFamily" Value="Segoe UI Semibold"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="Padding" Value="10,8"/>
|
||||
<Setter Property="BorderBrush" Value="#37394E"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,0,1"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="DataGridCell">
|
||||
<Setter Property="Padding" Value="8,6"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="DataGridCell">
|
||||
<Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}">
|
||||
<ContentPresenter VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#3C3F58"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrBlue}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="DataGridRow">
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#3C3F58"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- Card style for lists / rows -->
|
||||
<Style x:Key="CardStyle" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="8"/>
|
||||
<Setter Property="Background" Value="#23232A"/>
|
||||
<Setter Property="Padding" Value="12"/>
|
||||
<Setter Property="Margin" Value="6"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<!-- ================================================================
|
||||
MAIN LAYOUT : Sidebar | Content
|
||||
================================================================ -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="64"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ============= SIDEBAR ============= -->
|
||||
<Border Grid.Column="0" Background="#181825">
|
||||
<DockPanel LastChildFill="False">
|
||||
<!-- App icon -->
|
||||
<TextBlock DockPanel.Dock="Top" Text="BP"
|
||||
FontFamily="Segoe UI Black" FontSize="18"
|
||||
Foreground="{StaticResource BrBlue}"
|
||||
HorizontalAlignment="Center" Margin="0,16,0,12"/>
|
||||
<Border DockPanel.Dock="Top" Height="1" Background="#37394E" Margin="10,0"/>
|
||||
|
||||
<!-- Nav icons -->
|
||||
<StackPanel DockPanel.Dock="Top" Margin="0,8,0,0">
|
||||
<RadioButton x:Name="navFootball" Style="{StaticResource NavBtn}"
|
||||
IsChecked="True" ToolTip="Calcio"
|
||||
Checked="navFootball_Checked">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="20"
|
||||
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType=RadioButton}}"/>
|
||||
</RadioButton>
|
||||
<RadioButton x:Name="navRacing" Style="{StaticResource NavBtn}"
|
||||
ToolTip="Corse Cavalli"
|
||||
Checked="navRacing_Checked">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="20"
|
||||
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType=RadioButton}}"/>
|
||||
</RadioButton>
|
||||
<RadioButton x:Name="navVirtualFb" Style="{StaticResource NavBtn}"
|
||||
ToolTip="Calcio Virtuale"
|
||||
Checked="navVirtualFb_Checked">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="20"
|
||||
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType=RadioButton}}"/>
|
||||
</RadioButton>
|
||||
<RadioButton x:Name="navSettings" Style="{StaticResource NavBtn}"
|
||||
ToolTip="Impostazioni"
|
||||
Checked="navSettings_Checked">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="20"
|
||||
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType=RadioButton}}"/>
|
||||
</RadioButton>
|
||||
<!-- Info tab removed -->
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ============= CONTENT ============= -->
|
||||
<DockPanel Grid.Column="1">
|
||||
<!-- Header -->
|
||||
<Border DockPanel.Dock="Top" Height="52" Background="#181825">
|
||||
<TextBlock x:Name="lblTitle" Text="Calcio"
|
||||
FontFamily="Segoe UI Semibold" FontSize="20"
|
||||
Foreground="{StaticResource BrText}"
|
||||
VerticalAlignment="Center" Margin="24,0"/>
|
||||
</Border>
|
||||
<Border DockPanel.Dock="Top" Height="1" Background="#37394E"/>
|
||||
|
||||
<!-- Page host -->
|
||||
<Grid Background="{StaticResource BrBase}">
|
||||
|
||||
<!-- ==== PAGE: FOOTBALL ==== -->
|
||||
<Grid x:Name="pageFootball" Margin="24,16" Panel.ZIndex="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!-- Toolbar -->
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,12" Panel.ZIndex="20">
|
||||
<DatePicker x:Name="dpFootball" Width="160"
|
||||
Background="{StaticResource BrSurface0}"
|
||||
Foreground="{StaticResource BrText}"
|
||||
FontSize="13" VerticalContentAlignment="Center" IsHitTestVisible="True"/>
|
||||
<Button x:Name="btnDownloadFb" Content="Scarica Partite"
|
||||
Style="{StaticResource AccentBtn}"
|
||||
Background="{StaticResource BrBlue}" Margin="12,0,0,0"
|
||||
Click="btnDownloadFb_Click" IsHitTestVisible="True"/>
|
||||
<Button x:Name="btnExportFbCsv" Content="Esporta CSV"
|
||||
Style="{StaticResource AccentBtn}"
|
||||
Background="{StaticResource BrGreen}" Margin="8,0,0,0"
|
||||
IsEnabled="False"
|
||||
Click="btnExportFbCsv_Click" IsHitTestVisible="True"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Status -->
|
||||
<StackPanel Grid.Row="1" Margin="0,0,0,8">
|
||||
<ProgressBar x:Name="pbFootball" Style="{StaticResource ModernPb}" Margin="0,0,0,4"/>
|
||||
<TextBlock x:Name="lblStatusFb" Text="Pronto"
|
||||
FontSize="12" Foreground="{StaticResource BrSubtext0}"/>
|
||||
</StackPanel>
|
||||
<!-- Grid -->
|
||||
<DataGrid x:Name="dgFootball" Grid.Row="2" Style="{StaticResource ModernDg}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- ==== PAGE: HORSE RACING ==== -->
|
||||
<Grid x:Name="pageRacing" Margin="24,16" Visibility="Collapsed">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!-- Source selector: API or CSV -->
|
||||
<StackPanel Grid.Row="0" Margin="0,0,0,12">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<RadioButton x:Name="rbRcApi" Content="API" IsChecked="True" Foreground="{StaticResource BrText}" VerticalAlignment="Center" GroupName="RcSource" Checked="rbRcSource_Checked"/>
|
||||
<RadioButton x:Name="rbRcCsv" Content="CSV (Punters)" Foreground="{StaticResource BrText}" VerticalAlignment="Center" Margin="16,0,0,0" GroupName="RcSource" Checked="rbRcSource_Checked"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<!-- API controls -->
|
||||
<ComboBox x:Name="cmbDay" Width="140"
|
||||
Background="{StaticResource BrSurface0}"
|
||||
Foreground="{StaticResource BrText}"
|
||||
FontSize="13" VerticalContentAlignment="Center"/>
|
||||
<Button x:Name="btnDownloadRc" Content="Scarica Corse"
|
||||
Style="{StaticResource AccentBtn}"
|
||||
Background="{StaticResource BrBlue}" Margin="12,0,0,0"
|
||||
Click="btnDownloadRc_Click"/>
|
||||
<!-- CSV controls -->
|
||||
<Button x:Name="btnBrowseCsvRc" Content="Seleziona cartella CSV..."
|
||||
Style="{StaticResource AccentBtn}"
|
||||
Background="{StaticResource BrBlue}" Margin="12,0,0,0"
|
||||
Visibility="Collapsed"
|
||||
Click="btnBrowseCsvRc_Click"/>
|
||||
<!-- Export (always visible) -->
|
||||
<Button x:Name="btnExportRcCsv" Content="Esporta"
|
||||
Style="{StaticResource AccentBtn}"
|
||||
Background="{StaticResource BrGreen}" Margin="8,0,0,0"
|
||||
IsEnabled="False"
|
||||
Click="btnExportRcCsv_Click"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<!-- Status -->
|
||||
<StackPanel Grid.Row="1" Margin="0,0,0,8">
|
||||
<ProgressBar x:Name="pbRacing" Style="{StaticResource ModernPb}" Margin="0,0,0,4"/>
|
||||
<TextBlock x:Name="lblStatusRc" Text="Pronto"
|
||||
FontSize="12" Foreground="{StaticResource BrSubtext0}"/>
|
||||
</StackPanel>
|
||||
<!-- Grid -->
|
||||
<DataGrid x:Name="dgRacing" Grid.Row="2" Style="{StaticResource ModernDg}" AutoGeneratingColumn="dgRacing_AutoGeneratingColumn"/>
|
||||
</Grid>
|
||||
|
||||
<!-- ==== PAGE: SETTINGS ==== -->
|
||||
<ScrollViewer x:Name="pageSettings" Visibility="Collapsed"
|
||||
VerticalScrollBarVisibility="Auto" Padding="24,16">
|
||||
<StackPanel MaxWidth="600" HorizontalAlignment="Left">
|
||||
<TextBlock Text="Calcio — API" FontSize="16" FontFamily="Segoe UI Semibold"
|
||||
Foreground="{StaticResource BrBlue}" Margin="0,0,0,8"/>
|
||||
<Border Background="#282A3A" CornerRadius="10" Padding="20" Margin="0,0,0,20">
|
||||
<StackPanel>
|
||||
<TextBlock Text="API Key (api-football)" Foreground="{StaticResource BrText}"
|
||||
FontSize="13" Margin="0,0,0,6"/>
|
||||
<TextBox x:Name="txtApiKey" Style="{StaticResource FlatTb}"/>
|
||||
<!-- File name now built from prefix + date + suffix -->
|
||||
<Grid Margin="0,8,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Text="Prefisso" Foreground="{StaticResource BrText}" FontSize="13" Margin="0,0,0,6"/>
|
||||
<TextBox x:Name="txtFbPrefix" Style="{StaticResource FlatTb}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Margin="8,0,0,0">
|
||||
<TextBlock Text="Suffisso" Foreground="{StaticResource BrText}" FontSize="13" Margin="0,0,0,6"/>
|
||||
<TextBox x:Name="txtFbSuffix" Style="{StaticResource FlatTb}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<CheckBox x:Name="chkFbIncludeDate" IsChecked="True" Foreground="{StaticResource BrText}" VerticalAlignment="Center">Includi data</CheckBox>
|
||||
<ComboBox x:Name="cmbFbDateFormat" Width="180" Margin="12,0,0,0" Background="{StaticResource BrSurface0}" Foreground="Black">
|
||||
<ComboBoxItem Content="yyyy-MM-dd"/>
|
||||
<ComboBoxItem Content="dd-MM-yyyy"/>
|
||||
<ComboBoxItem Content="yyyyMMdd"/>
|
||||
<ComboBoxItem Content="ddMMyyyy"/>
|
||||
<ComboBoxItem Content="yyyy-MM-dd_HH-mm"/>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<TextBlock Text="Anteprima nome file:" Foreground="{StaticResource BrSubtext0}" Margin="0,8,0,4"/>
|
||||
<TextBlock x:Name="txtFbPreview" FontFamily="Segoe UI" FontSize="13" Foreground="{StaticResource BrText}" />
|
||||
<TextBlock Text="Formato esportazione" Foreground="{StaticResource BrText}" FontSize="13" Margin="0,12,0,6"/>
|
||||
<ComboBox x:Name="cmbFbFormat" Width="160" SelectedIndex="0" Background="{StaticResource BrSurface0}" Foreground="Black">
|
||||
<ComboBoxItem Content="CSV"/>
|
||||
<ComboBoxItem Content="JSON"/>
|
||||
<ComboBoxItem Content="XML"/>
|
||||
</ComboBox>
|
||||
<TextBlock Text="Cartella esportazione CSV" Foreground="{StaticResource BrText}"
|
||||
FontSize="13" Margin="0,14,0,6"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox x:Name="txtFbExportPath" Style="{StaticResource FlatTb}" IsReadOnly="True"/>
|
||||
<Button Grid.Column="1" Content="Sfoglia..." Margin="8,0,0,0"
|
||||
Style="{StaticResource AccentBtn}" Background="{StaticResource BrSurface2}"
|
||||
Foreground="{StaticResource BrText}"
|
||||
Click="btnBrowseFbExport_Click"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- HORSE RACING API -->
|
||||
<TextBlock Text="Corse Cavalli — API" FontSize="16" FontFamily="Segoe UI Semibold"
|
||||
Foreground="{StaticResource BrBlue}" Margin="0,32,0,8"/>
|
||||
<Border Background="#282A3A" CornerRadius="10" Padding="20" Margin="0,0,0,20">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Username" Foreground="{StaticResource BrText}"
|
||||
FontSize="13" Margin="0,0,0,6"/>
|
||||
<TextBox x:Name="txtRacingUser" Style="{StaticResource FlatTb}"/>
|
||||
<!-- File name now built from prefix + date + suffix -->
|
||||
<Grid Margin="0,8,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Text="Prefisso" Foreground="{StaticResource BrText}" FontSize="13" Margin="0,0,0,6"/>
|
||||
<TextBox x:Name="txtRcPrefix" Style="{StaticResource FlatTb}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Margin="8,0,0,0">
|
||||
<TextBlock Text="Suffisso" Foreground="{StaticResource BrText}" FontSize="13" Margin="0,0,0,6"/>
|
||||
<TextBox x:Name="txtRcSuffix" Style="{StaticResource FlatTb}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<CheckBox x:Name="chkRcIncludeDate" IsChecked="True" Foreground="{StaticResource BrText}" VerticalAlignment="Center">Includi data</CheckBox>
|
||||
<ComboBox x:Name="cmbRcDateFormat" Width="180" Margin="12,0,0,0" Background="{StaticResource BrSurface0}" Foreground="Black">
|
||||
<ComboBoxItem Content="yyyy-MM-dd"/>
|
||||
<ComboBoxItem Content="dd-MM-yyyy"/>
|
||||
<ComboBoxItem Content="yyyyMMdd"/>
|
||||
<ComboBoxItem Content="ddMMyyyy"/>
|
||||
<ComboBoxItem Content="yyyy-MM-dd_HH-mm"/>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<TextBlock Text="Anteprima nome file:" Foreground="{StaticResource BrSubtext0}" Margin="0,8,0,4"/>
|
||||
<TextBlock x:Name="txtRcPreview" FontFamily="Segoe UI" FontSize="13" Foreground="{StaticResource BrText}" />
|
||||
<TextBlock Text="Formato esportazione" Foreground="{StaticResource BrText}" FontSize="13" Margin="0,12,0,6"/>
|
||||
<ComboBox x:Name="cmbRcFormat" Width="160" SelectedIndex="0" Background="{StaticResource BrSurface0}" Foreground="Black">
|
||||
<ComboBoxItem Content="CSV"/>
|
||||
<ComboBoxItem Content="JSON"/>
|
||||
<ComboBoxItem Content="XML"/>
|
||||
</ComboBox>
|
||||
<TextBlock Text="Password" Foreground="{StaticResource BrText}"
|
||||
FontSize="13" Margin="0,14,0,6"/>
|
||||
<PasswordBox x:Name="txtRacingPass" Style="{StaticResource FlatPb}"/>
|
||||
<TextBlock Text="Cartella esportazione CSV" Foreground="{StaticResource BrText}"
|
||||
FontSize="13" Margin="0,14,0,6"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox x:Name="txtRcExportPath" Style="{StaticResource FlatTb}" IsReadOnly="True"/>
|
||||
<Button Grid.Column="1" Content="Sfoglia..." Margin="8,0,0,0"
|
||||
Style="{StaticResource AccentBtn}" Background="{StaticResource BrSurface2}"
|
||||
Foreground="{StaticResource BrText}"
|
||||
Click="btnBrowseRcExport_Click"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- SAVE -->
|
||||
<Button x:Name="btnSaveSettings" Content="Salva Impostazioni"
|
||||
Style="{StaticResource AccentBtn}"
|
||||
Background="{StaticResource BrGreen}"
|
||||
HorizontalAlignment="Left" Margin="0,4,0,24"
|
||||
Click="btnSaveSettings_Click"/>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- ==== PAGE: VIRTUAL FOOTBALL ==== -->
|
||||
<Grid x:Name="pageVirtualFb" Margin="0" Visibility="Collapsed">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" MinWidth="400"/>
|
||||
<ColumnDefinition Width="360"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- LEFT: WebBrowser -->
|
||||
<Border Grid.Column="0" Background="#181825" Margin="8">
|
||||
<DockPanel>
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="8,8,8,4">
|
||||
<Button x:Name="btnVfbNavigate" Content="Vai"
|
||||
Style="{StaticResource AccentBtn}" Background="{StaticResource BrBlue}"
|
||||
Margin="0,0,8,0" Click="btnVfbNavigate_Click"/>
|
||||
<TextBox x:Name="txtVfbUrl" Style="{StaticResource FlatTb}"
|
||||
Text="https://www.bet365.it/#/IP/B151"
|
||||
Width="500" VerticalContentAlignment="Center"/>
|
||||
<Button x:Name="btnVfbRefresh" Content=""
|
||||
FontFamily="Segoe MDL2 Assets" FontSize="14"
|
||||
Style="{StaticResource AccentBtn}" Background="{StaticResource BrSurface2}"
|
||||
Foreground="{StaticResource BrText}" Margin="8,0,0,0"
|
||||
Click="btnVfbRefresh_Click" ToolTip="Aggiorna"/>
|
||||
</StackPanel>
|
||||
<wv2:WebView2 x:Name="wbVirtualFb" Margin="8,0,8,8"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<!-- RIGHT: Results Panel -->
|
||||
<Border Grid.Column="1" Background="#282A3A" CornerRadius="10" Margin="0,8,8,8" Padding="12">
|
||||
<DockPanel>
|
||||
<TextBlock DockPanel.Dock="Top" Text="Ultimi Risultati"
|
||||
FontFamily="Segoe UI Semibold" FontSize="16"
|
||||
Foreground="{StaticResource BrBlue}" Margin="0,0,0,8"/>
|
||||
|
||||
<!-- Add result form -->
|
||||
<Border DockPanel.Dock="Top" Background="#313244" CornerRadius="8" Padding="10" Margin="0,0,0,8">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Aggiungi Risultato" FontSize="13"
|
||||
Foreground="{StaticResource BrSubtext0}" Margin="0,0,0,6"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="40"/>
|
||||
<ColumnDefinition Width="20"/>
|
||||
<ColumnDefinition Width="40"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox x:Name="txtVfbHome" Style="{StaticResource FlatTb}"
|
||||
Text="Casa" FontSize="12"/>
|
||||
<TextBox x:Name="txtVfbHomeGoals" Grid.Column="1" Style="{StaticResource FlatTb}"
|
||||
Text="0" FontSize="12" TextAlignment="Center" Margin="4,0"/>
|
||||
<TextBlock Grid.Column="2" Text="-" Foreground="{StaticResource BrText}"
|
||||
FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
<TextBox x:Name="txtVfbAwayGoals" Grid.Column="3" Style="{StaticResource FlatTb}"
|
||||
Text="0" FontSize="12" TextAlignment="Center" Margin="4,0"/>
|
||||
<TextBox x:Name="txtVfbAway" Grid.Column="4" Style="{StaticResource FlatTb}"
|
||||
Text="Ospite" FontSize="12"/>
|
||||
</Grid>
|
||||
<Button x:Name="btnVfbAddResult" Content="Aggiungi"
|
||||
Style="{StaticResource AccentBtn}" Background="{StaticResource BrBlue}"
|
||||
HorizontalAlignment="Left" Margin="0,8,0,0"
|
||||
Click="btnVfbAddResult_Click"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Suggested bet -->
|
||||
<Border DockPanel.Dock="Top" Background="#313244" CornerRadius="8" Padding="10" Margin="0,0,0,8">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Puntata Consigliata" FontSize="13"
|
||||
FontFamily="Segoe UI Semibold" Foreground="{StaticResource BrPeach}" Margin="0,0,0,4"/>
|
||||
<TextBlock x:Name="lblVfbSuggestion" Text="Inserisci almeno 5 risultati"
|
||||
FontSize="12" Foreground="{StaticResource BrText}" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Stats -->
|
||||
<Border DockPanel.Dock="Top" Background="#313244" CornerRadius="8" Padding="10" Margin="0,0,0,8">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Statistiche" FontSize="13"
|
||||
FontFamily="Segoe UI Semibold" Foreground="{StaticResource BrLavender}" Margin="0,0,0,4"/>
|
||||
<TextBlock x:Name="lblVfbStats" Text="Nessun dato"
|
||||
FontSize="12" Foreground="{StaticResource BrText}" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Results list -->
|
||||
<ListBox x:Name="lbVfbResults" Background="Transparent" BorderThickness="0"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border CornerRadius="6" Padding="10,6" Margin="0,2"
|
||||
Background="{Binding RowColor}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="{Binding Time}"
|
||||
FontSize="11" Foreground="#A6ADC8"
|
||||
VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||
<TextBlock Grid.Column="1" FontSize="12" VerticalAlignment="Center">
|
||||
<Run Text="{Binding Home, Mode=OneWay}" Foreground="#CDD6F4"/>
|
||||
<Run Text=" "/>
|
||||
<Run Text="{Binding Score, Mode=OneWay}" Foreground="White" FontFamily="Segoe UI Semibold"/>
|
||||
<Run Text=" "/>
|
||||
<Run Text="{Binding Away, Mode=OneWay}" Foreground="#CDD6F4"/>
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="2" Text="{Binding Outcome}"
|
||||
FontSize="12" FontFamily="Segoe UI Semibold"
|
||||
Foreground="White" VerticalAlignment="Center" Margin="8,0,0,0"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- Info page removed -->
|
||||
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
1114
HorseRacingPredictor/HorseRacingPredictor/MainWindow.xaml.cs
Normal file
1114
HorseRacingPredictor/HorseRacingPredictor/MainWindow.xaml.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,88 +0,0 @@
|
||||
/****** Object: StoredProcedure [dbo].[GetFavoriteHorses] Script Date: 17/07/2025 09:09:35 ******/
|
||||
SET ANSI_NULLS ON
|
||||
GO
|
||||
|
||||
SET QUOTED_IDENTIFIER ON
|
||||
GO
|
||||
|
||||
ALTER PROCEDURE [dbo].[GetFavoriteHorses]
|
||||
@Date DATETIME = NULL,
|
||||
@Meeting NVARCHAR(100) = NULL,
|
||||
@RaceNumber INT = NULL,
|
||||
@TopN INT = 3,
|
||||
@Weight_HandicapRating DECIMAL(10,2) = 1,
|
||||
@Weight_CareerWins DECIMAL(10,2) = 1,
|
||||
@Weight_CareerStrikeRate DECIMAL(10,2) = 1,
|
||||
@Weight_JockeyLast100StrikeRate DECIMAL(10,2) = 1,
|
||||
@Weight_TrainerLast100StrikeRate DECIMAL(10,2) = 1,
|
||||
@Weight_BestFixedOdds DECIMAL(10,2) = 1,
|
||||
@Weight_Age DECIMAL(10,2) = 1,
|
||||
@Weight_CareerPlacings DECIMAL(10,2) = 1,
|
||||
@Weight_DryTrackStrikeRate DECIMAL(10,2) = 1,
|
||||
@Weight_ThisTrackStrikeRate DECIMAL(10,2) = 1,
|
||||
@Weight_LastStartFinishPosition DECIMAL(10,2) = 1,
|
||||
@Weight_WeightCarried DECIMAL(10,2) = 1
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
-- Crea tabella temporanea per i risultati
|
||||
CREATE TABLE #Results (
|
||||
DataCorsa NVARCHAR(10),
|
||||
LuogoCorsa NVARCHAR(100),
|
||||
NumeroCorsa INT,
|
||||
NomeCavallo NVARCHAR(100),
|
||||
Punteggio DECIMAL(18,4),
|
||||
RisultatoFinale NVARCHAR(50),
|
||||
PosizioneArrivo INT,
|
||||
PrevistoVincente BIT
|
||||
);
|
||||
|
||||
WITH Scoring AS (
|
||||
SELECT
|
||||
Data,
|
||||
Meeting,
|
||||
Race,
|
||||
HorseName,
|
||||
-- Calcolo del punteggio pesato con le nuove statistiche
|
||||
(
|
||||
ISNULL(HandicapRating,0) * @Weight_HandicapRating +
|
||||
ISNULL(CareerWins,0) * @Weight_CareerWins +
|
||||
ISNULL(CareerStrikeRate,0) * @Weight_CareerStrikeRate +
|
||||
ISNULL(JockeyLast100StrikeRate,0) * @Weight_JockeyLast100StrikeRate +
|
||||
ISNULL(TrainerLast100StrikeRate,0) * @Weight_TrainerLast100StrikeRate +
|
||||
ISNULL(BestFixedOdds,0) * @Weight_BestFixedOdds +
|
||||
ISNULL(Age,0) * @Weight_Age +
|
||||
ISNULL(CareerPlacings,0) * @Weight_CareerPlacings +
|
||||
ISNULL(DryTrackStrikeRate,0) * @Weight_DryTrackStrikeRate +
|
||||
ISNULL(ThisTrackStrikeRate,0) * @Weight_ThisTrackStrikeRate +
|
||||
-- Per LastStartFinishPosition, valori più bassi sono migliori, quindi invertiamo il segno
|
||||
(CASE WHEN TRY_CAST(LastStartFinishPosition AS INT) > 0 THEN (1.0 / TRY_CAST(LastStartFinishPosition AS FLOAT)) ELSE 0 END) * @Weight_LastStartFinishPosition +
|
||||
ISNULL(WeightCarried,0) * @Weight_WeightCarried
|
||||
) AS Score,
|
||||
FinishResult
|
||||
FROM Races
|
||||
WHERE (FinishResult IS NOT NULL AND FinishResult <> '')
|
||||
),
|
||||
Ranked AS (
|
||||
SELECT *,
|
||||
ROW_NUMBER() OVER (PARTITION BY Data, Meeting, Race ORDER BY Score DESC) AS RankByScore
|
||||
FROM Scoring
|
||||
)
|
||||
INSERT INTO #Results
|
||||
SELECT
|
||||
CONVERT(VARCHAR(10), Data, 120),
|
||||
Meeting,
|
||||
Race,
|
||||
HorseName,
|
||||
Score,
|
||||
FinishResult,
|
||||
CASE WHEN ISNUMERIC(FinishResult) = 1 THEN CAST(FinishResult AS INT) ELSE NULL END,
|
||||
CASE WHEN RankByScore = 1 THEN 1 ELSE 0 END
|
||||
FROM Ranked
|
||||
WHERE RankByScore = 1;
|
||||
|
||||
SELECT * FROM #Results;
|
||||
|
||||
DROP TABLE #Results;
|
||||
END
|
||||
@@ -1,27 +0,0 @@
|
||||
/****** Object: View [dbo].[GetValidHorses] Script Date: 17/07/2025 09:10:07 ******/
|
||||
SET ANSI_NULLS ON
|
||||
GO
|
||||
|
||||
SET QUOTED_IDENTIFIER ON
|
||||
GO
|
||||
|
||||
CREATE VIEW [dbo].[GetValidHorses]
|
||||
AS
|
||||
SELECT Data, Meeting, Race, Num, HorseName, Age, Gender, HandicapRating, CareerRuns, CareerWins, CareerStrikeRate, CareerROI, CareerPlacings, CareerPlaceStrikeRate, DryTrackRuns, DryTrackWins, DryTrackStrikeRate,
|
||||
DryTrackROI, WetTrackRuns, WetTrackWins, WetTrackStrikeRate, WetTrackROI, AveragePrizeMoney, CareerPrizeMoney, BestFixedOdds, BetEasyOdds, Weight, WeightCarried, Barrier, PrizeMoney, ThisTrackRuns,
|
||||
ThisTrackWins, ThisTrackStrikeRate, ThisTrackROI, ThisTrackPlaces, ThisTrackPlaceStrikeRate, ThisDistanceRuns, ThisDistanceWins, ThisDistanceStrikeRate, ThisDistanceROI, ThisDistancePlaces,
|
||||
ThisDistancePlaceStrikeRate, ThisTrackDistanceRuns, ThisTrackDistanceWins, ThisTrackDistanceStrikeRate, ThisTrackDistanceROI, ThisTrackDistancePlaces, ThisTrackDistancePlaceStrikeRate, ThisConditionRuns,
|
||||
ThisConditionWins, ThisConditionStrikeRate, ThisConditionROI, ThisConditionPlaces, ThisConditionPlaceStrikeRate, Jockey, Apprentice, JockeyWeightClaim, JockeyLast100HorseEarnings, JockeyLast100AvgHorseEarnings,
|
||||
JockeyLast100Starts, JockeyLast100Wins, JockeyLast100StrikeRate, JockeyLast100ROI, JockeyLast100Places, JockeyLast100PlaceStrikeRate, Jockey12MonthHorseEarnings, Jockey12MonthAvgHorseEarnings,
|
||||
Jockey12MonthsStarts, Jockey12MonthsWins, Jockey12MonthsStrikeRate, Jockey12MonthsROI, Jockey12MonthsPlaces, Jockey12MonthsPlaceStrikeRate, JockeyThisSeasonHorseEarnings,
|
||||
JockeyThisSeasonAvgHorseEarnings, JockeyThisSeasonStarts, JockeyThisSeasonWins, JockeyThisSeasonStrikeRate, JockeyThisSeasonROI, JockeyThisSeasonPlaces, JockeyThisSeasonPlaceStrikeRate,
|
||||
JockeyLastSeasonHorseEarnings, JockeyLastSeasonAvgHorseEarnings, JockeyLastSeasonStarts, JockeyLastSeasonWins, JockeyLastSeasonStrikeRate, JockeyLastSeasonROI, JockeyLastSeasonPlaces,
|
||||
JockeyLastSeasonPlaceStrikeRate, Trainer, TrainerLast100HorseEarnings, TrainerLast100AvgHorseEarnings, TrainerLast100Starts, TrainerLast100Wins, TrainerLast100StrikeRate, TrainerLast100ROI, TrainerLast100Places,
|
||||
TrainerLast100PlaceStrikeRate, Trainer12MonthHorseEarnings, Trainer12MonthAvgHorseEarnings, Trainer12MonthsStarts, Trainer12MonthsWins, Trainer12MonthsStrikeRate, Trainer12MonthsROI, Trainer12MonthsPlaces,
|
||||
Trainer12MonthsPlaceStrikeRate, TrainerThisSeasonHorseEarnings, TrainerThisSeasonAvgHorseEarnings, TrainerThisSeasonStarts, TrainerThisSeasonWins, TrainerThisSeasonStrikeRate, TrainerThisSeasonROI,
|
||||
TrainerThisSeasonPlaces, TrainerThisSeasonPlaceStrikeRate, TrainerLastSeasonHorseEarnings, TrainerLastSeasonAvgHorseEarnings, TrainerLastSeasonStarts, TrainerLastSeasonWins, TrainerLastSeasonStrikeRate,
|
||||
TrainerLastSeasonROI, TrainerLastSeasonPlaces, TrainerLastSeasonPlaceStrikeRate, LastStartFinishPosition, LastStartMargin, LastStartDistance, LastStartDistanceChange, LastStartPrizeMoney, FinishResult
|
||||
FROM dbo.Races
|
||||
WHERE (FinishResult <> '') OR
|
||||
(FinishResult IS NOT NULL)
|
||||
GO
|
||||
@@ -1,20 +0,0 @@
|
||||
CREATE TABLE [dbo].[PredictionScanResults] (
|
||||
ScanId INT IDENTITY(1,1) PRIMARY KEY,
|
||||
SessionId UNIQUEIDENTIFIER NOT NULL,
|
||||
ScanDate DATETIME NOT NULL DEFAULT GETDATE(),
|
||||
Weight_HandicapRating DECIMAL(10,2) NOT NULL,
|
||||
Weight_CareerWins DECIMAL(10,2) NOT NULL,
|
||||
Weight_CareerStrikeRate DECIMAL(10,2) NOT NULL,
|
||||
Weight_JockeyLast100StrikeRate DECIMAL(10,2) NOT NULL,
|
||||
Weight_TrainerLast100StrikeRate DECIMAL(10,2) NOT NULL,
|
||||
Weight_BestFixedOdds DECIMAL(10,2) NOT NULL,
|
||||
Weight_Age DECIMAL(10,2) NOT NULL,
|
||||
Weight_CareerPlacings DECIMAL(10,2) NOT NULL,
|
||||
Weight_DryTrackStrikeRate DECIMAL(10,2) NOT NULL,
|
||||
Weight_ThisTrackStrikeRate DECIMAL(10,2) NOT NULL,
|
||||
Weight_LastStartFinishPosition DECIMAL(10,2) NOT NULL,
|
||||
Weight_WeightCarried DECIMAL(10,2) NOT NULL,
|
||||
TotalRaces INT NOT NULL,
|
||||
CorrectPredictions INT NOT NULL,
|
||||
WinPercentage DECIMAL(5,2) NOT NULL
|
||||
)
|
||||
@@ -1,152 +0,0 @@
|
||||
/****** Object: Table [dbo].[Races] Script Date: 16/07/2025 23:27:12 ******/
|
||||
SET ANSI_NULLS ON
|
||||
GO
|
||||
|
||||
SET QUOTED_IDENTIFIER ON
|
||||
GO
|
||||
|
||||
CREATE TABLE [dbo].[Races](
|
||||
[Data] [datetime] NOT NULL,
|
||||
[Meeting] [nvarchar](100) NOT NULL,
|
||||
[Race] [int] NOT NULL,
|
||||
[Num] [int] NOT NULL,
|
||||
[FileName] [nvarchar](255) NULL,
|
||||
[HorseName] [nvarchar](100) NULL,
|
||||
[Age] [int] NULL,
|
||||
[Gender] [nvarchar](10) NULL,
|
||||
[HandicapRating] [decimal](10, 2) NULL,
|
||||
[CareerRuns] [int] NULL,
|
||||
[CareerWins] [int] NULL,
|
||||
[CareerStrikeRate] [decimal](10, 2) NULL,
|
||||
[CareerROI] [decimal](10, 2) NULL,
|
||||
[CareerPlacings] [int] NULL,
|
||||
[CareerPlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[DryTrackRuns] [int] NULL,
|
||||
[DryTrackWins] [int] NULL,
|
||||
[DryTrackStrikeRate] [decimal](10, 2) NULL,
|
||||
[DryTrackROI] [decimal](10, 2) NULL,
|
||||
[WetTrackRuns] [int] NULL,
|
||||
[WetTrackWins] [int] NULL,
|
||||
[WetTrackStrikeRate] [decimal](10, 2) NULL,
|
||||
[WetTrackROI] [decimal](10, 2) NULL,
|
||||
[AveragePrizeMoney] [decimal](15, 2) NULL,
|
||||
[CareerPrizeMoney] [decimal](15, 2) NULL,
|
||||
[BestFixedOdds] [decimal](10, 2) NULL,
|
||||
[BetEasyOdds] [decimal](10, 2) NULL,
|
||||
[Weight] [decimal](10, 2) NULL,
|
||||
[WeightCarried] [decimal](10, 2) NULL,
|
||||
[Barrier] [nvarchar](10) NULL,
|
||||
[PrizeMoney] [decimal](15, 2) NULL,
|
||||
[ThisTrackRuns] [int] NULL,
|
||||
[ThisTrackWins] [int] NULL,
|
||||
[ThisTrackStrikeRate] [decimal](10, 2) NULL,
|
||||
[ThisTrackROI] [decimal](10, 2) NULL,
|
||||
[ThisTrackPlaces] [int] NULL,
|
||||
[ThisTrackPlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[ThisDistanceRuns] [int] NULL,
|
||||
[ThisDistanceWins] [int] NULL,
|
||||
[ThisDistanceStrikeRate] [decimal](10, 2) NULL,
|
||||
[ThisDistanceROI] [decimal](10, 2) NULL,
|
||||
[ThisDistancePlaces] [int] NULL,
|
||||
[ThisDistancePlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[ThisTrackDistanceRuns] [int] NULL,
|
||||
[ThisTrackDistanceWins] [int] NULL,
|
||||
[ThisTrackDistanceStrikeRate] [decimal](10, 2) NULL,
|
||||
[ThisTrackDistanceROI] [decimal](10, 2) NULL,
|
||||
[ThisTrackDistancePlaces] [int] NULL,
|
||||
[ThisTrackDistancePlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[ThisConditionRuns] [int] NULL,
|
||||
[ThisConditionWins] [int] NULL,
|
||||
[ThisConditionStrikeRate] [decimal](10, 2) NULL,
|
||||
[ThisConditionROI] [decimal](10, 2) NULL,
|
||||
[ThisConditionPlaces] [int] NULL,
|
||||
[ThisConditionPlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[Jockey] [nvarchar](100) NULL,
|
||||
[Apprentice] [nvarchar](10) NULL,
|
||||
[JockeyWeightClaim] [decimal](10, 2) NULL,
|
||||
[JockeyLast100HorseEarnings] [decimal](15, 2) NULL,
|
||||
[JockeyLast100AvgHorseEarnings] [decimal](15, 2) NULL,
|
||||
[JockeyLast100Starts] [int] NULL,
|
||||
[JockeyLast100Wins] [int] NULL,
|
||||
[JockeyLast100StrikeRate] [decimal](10, 2) NULL,
|
||||
[JockeyLast100ROI] [decimal](10, 2) NULL,
|
||||
[JockeyLast100Places] [int] NULL,
|
||||
[JockeyLast100PlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[Jockey12MonthHorseEarnings] [decimal](15, 2) NULL,
|
||||
[Jockey12MonthAvgHorseEarnings] [decimal](15, 2) NULL,
|
||||
[Jockey12MonthsStarts] [int] NULL,
|
||||
[Jockey12MonthsWins] [int] NULL,
|
||||
[Jockey12MonthsStrikeRate] [decimal](10, 2) NULL,
|
||||
[Jockey12MonthsROI] [decimal](10, 2) NULL,
|
||||
[Jockey12MonthsPlaces] [int] NULL,
|
||||
[Jockey12MonthsPlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[JockeyThisSeasonHorseEarnings] [decimal](15, 2) NULL,
|
||||
[JockeyThisSeasonAvgHorseEarnings] [decimal](15, 2) NULL,
|
||||
[JockeyThisSeasonStarts] [int] NULL,
|
||||
[JockeyThisSeasonWins] [int] NULL,
|
||||
[JockeyThisSeasonStrikeRate] [decimal](10, 2) NULL,
|
||||
[JockeyThisSeasonROI] [decimal](10, 2) NULL,
|
||||
[JockeyThisSeasonPlaces] [int] NULL,
|
||||
[JockeyThisSeasonPlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[JockeyLastSeasonHorseEarnings] [decimal](15, 2) NULL,
|
||||
[JockeyLastSeasonAvgHorseEarnings] [decimal](15, 2) NULL,
|
||||
[JockeyLastSeasonStarts] [int] NULL,
|
||||
[JockeyLastSeasonWins] [int] NULL,
|
||||
[JockeyLastSeasonStrikeRate] [decimal](10, 2) NULL,
|
||||
[JockeyLastSeasonROI] [decimal](10, 2) NULL,
|
||||
[JockeyLastSeasonPlaces] [int] NULL,
|
||||
[JockeyLastSeasonPlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[Trainer] [nvarchar](100) NULL,
|
||||
[TrainerLast100HorseEarnings] [decimal](15, 2) NULL,
|
||||
[TrainerLast100AvgHorseEarnings] [decimal](15, 2) NULL,
|
||||
[TrainerLast100Starts] [int] NULL,
|
||||
[TrainerLast100Wins] [int] NULL,
|
||||
[TrainerLast100StrikeRate] [decimal](10, 2) NULL,
|
||||
[TrainerLast100ROI] [decimal](10, 2) NULL,
|
||||
[TrainerLast100Places] [int] NULL,
|
||||
[TrainerLast100PlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[Trainer12MonthHorseEarnings] [decimal](15, 2) NULL,
|
||||
[Trainer12MonthAvgHorseEarnings] [decimal](15, 2) NULL,
|
||||
[Trainer12MonthsStarts] [int] NULL,
|
||||
[Trainer12MonthsWins] [int] NULL,
|
||||
[Trainer12MonthsStrikeRate] [decimal](10, 2) NULL,
|
||||
[Trainer12MonthsROI] [decimal](10, 2) NULL,
|
||||
[Trainer12MonthsPlaces] [int] NULL,
|
||||
[Trainer12MonthsPlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[TrainerThisSeasonHorseEarnings] [decimal](15, 2) NULL,
|
||||
[TrainerThisSeasonAvgHorseEarnings] [decimal](15, 2) NULL,
|
||||
[TrainerThisSeasonStarts] [int] NULL,
|
||||
[TrainerThisSeasonWins] [int] NULL,
|
||||
[TrainerThisSeasonStrikeRate] [decimal](10, 2) NULL,
|
||||
[TrainerThisSeasonROI] [decimal](10, 2) NULL,
|
||||
[TrainerThisSeasonPlaces] [int] NULL,
|
||||
[TrainerThisSeasonPlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[TrainerLastSeasonHorseEarnings] [decimal](15, 2) NULL,
|
||||
[TrainerLastSeasonAvgHorseEarnings] [decimal](15, 2) NULL,
|
||||
[TrainerLastSeasonStarts] [int] NULL,
|
||||
[TrainerLastSeasonWins] [int] NULL,
|
||||
[TrainerLastSeasonStrikeRate] [decimal](10, 2) NULL,
|
||||
[TrainerLastSeasonROI] [decimal](10, 2) NULL,
|
||||
[TrainerLastSeasonPlaces] [int] NULL,
|
||||
[TrainerLastSeasonPlaceStrikeRate] [decimal](10, 2) NULL,
|
||||
[LastStartFinishPosition] [nvarchar](10) NULL,
|
||||
[LastStartMargin] [decimal](10, 2) NULL,
|
||||
[LastStartDistance] [decimal](10, 2) NULL,
|
||||
[LastStartDistanceChange] [decimal](10, 2) NULL,
|
||||
[LastStartPrizeMoney] [decimal](15, 2) NULL,
|
||||
[FormGuideUrl] [nvarchar](500) NULL,
|
||||
[HorseProfileUrl] [nvarchar](500) NULL,
|
||||
[JockeyProfileUrl] [nvarchar](500) NULL,
|
||||
[TrainerProfileUrl] [nvarchar](500) NULL,
|
||||
[FinishResult] [nvarchar](50) NULL,
|
||||
[Created] [datetime] NOT NULL,
|
||||
[Updated] [datetime] NOT NULL,
|
||||
CONSTRAINT [PK_Races] PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[Data] ASC,
|
||||
[Meeting] ASC,
|
||||
[Race] ASC,
|
||||
[Num] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
@@ -1,228 +0,0 @@
|
||||
ALTER PROCEDURE [dbo].[ScanFavoriteHorseWeights]
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
DECLARE @MinValue INT = 1
|
||||
DECLARE @MaxValue INT = 3 -- Modifica per range più ampi
|
||||
DECLARE @SessionId UNIQUEIDENTIFIER = NEWID()
|
||||
DECLARE @ScanDate DATETIME = GETDATE()
|
||||
|
||||
-- Parametri
|
||||
DECLARE @Weight_HandicapRating INT
|
||||
DECLARE @Weight_CareerWins INT
|
||||
DECLARE @Weight_CareerStrikeRate INT
|
||||
DECLARE @Weight_JockeyLast100StrikeRate INT
|
||||
DECLARE @Weight_TrainerLast100StrikeRate INT
|
||||
DECLARE @Weight_BestFixedOdds INT
|
||||
DECLARE @Weight_Age INT
|
||||
DECLARE @Weight_CareerPlacings INT
|
||||
DECLARE @Weight_DryTrackStrikeRate INT
|
||||
DECLARE @Weight_ThisTrackStrikeRate INT
|
||||
DECLARE @Weight_LastStartFinishPosition INT
|
||||
DECLARE @Weight_WeightCarried INT
|
||||
|
||||
DECLARE @TotalRaces INT, @CorrectPredictions INT, @WinPercentage DECIMAL(5,2)
|
||||
DECLARE @CombinazioniTotali BIGINT
|
||||
DECLARE @CombinazioneCorrente BIGINT = 0
|
||||
|
||||
-- Carica tutti i cavalli validi in memoria
|
||||
IF OBJECT_ID('tempdb..#AllHorses') IS NOT NULL DROP TABLE #AllHorses
|
||||
SELECT
|
||||
Data,
|
||||
Meeting,
|
||||
Race,
|
||||
HorseName,
|
||||
HandicapRating,
|
||||
CareerWins,
|
||||
CareerStrikeRate,
|
||||
JockeyLast100StrikeRate,
|
||||
TrainerLast100StrikeRate,
|
||||
BestFixedOdds,
|
||||
Age,
|
||||
CareerPlacings,
|
||||
DryTrackStrikeRate,
|
||||
ThisTrackStrikeRate,
|
||||
LastStartFinishPosition,
|
||||
WeightCarried,
|
||||
FinishResult
|
||||
INTO #AllHorses
|
||||
FROM Races
|
||||
WHERE (FinishResult IS NOT NULL AND FinishResult <> '')
|
||||
|
||||
-- Conta il numero di corse distinte
|
||||
SELECT @TotalRaces = COUNT(DISTINCT
|
||||
CONVERT(NVARCHAR(20), Data, 120) + '_' + Meeting + '_' + CAST(Race AS NVARCHAR(10))
|
||||
)
|
||||
FROM #AllHorses
|
||||
|
||||
-- Calcola il numero totale di combinazioni
|
||||
SET @CombinazioniTotali = POWER(@MaxValue - @MinValue + 1, 12)
|
||||
|
||||
-- Inizializza la sessione con un record "vuoto"
|
||||
INSERT INTO PredictionScanResults (
|
||||
SessionId, ScanDate,
|
||||
Weight_HandicapRating, Weight_CareerWins, Weight_CareerStrikeRate, Weight_JockeyLast100StrikeRate,
|
||||
Weight_TrainerLast100StrikeRate, Weight_BestFixedOdds, Weight_Age, Weight_CareerPlacings,
|
||||
Weight_DryTrackStrikeRate, Weight_ThisTrackStrikeRate, Weight_LastStartFinishPosition, Weight_WeightCarried,
|
||||
TotalRaces, CorrectPredictions, WinPercentage
|
||||
) VALUES (
|
||||
@SessionId, @ScanDate,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0
|
||||
)
|
||||
|
||||
SET @Weight_HandicapRating = @MinValue
|
||||
WHILE @Weight_HandicapRating <= @MaxValue
|
||||
BEGIN
|
||||
SET @Weight_CareerWins = @MinValue
|
||||
WHILE @Weight_CareerWins <= @MaxValue
|
||||
BEGIN
|
||||
SET @Weight_CareerStrikeRate = @MinValue
|
||||
WHILE @Weight_CareerStrikeRate <= @MaxValue
|
||||
BEGIN
|
||||
SET @Weight_JockeyLast100StrikeRate = @MinValue
|
||||
WHILE @Weight_JockeyLast100StrikeRate <= @MaxValue
|
||||
BEGIN
|
||||
SET @Weight_TrainerLast100StrikeRate = @MinValue
|
||||
WHILE @Weight_TrainerLast100StrikeRate <= @MaxValue
|
||||
BEGIN
|
||||
SET @Weight_BestFixedOdds = @MinValue
|
||||
WHILE @Weight_BestFixedOdds <= @MaxValue
|
||||
BEGIN
|
||||
SET @Weight_Age = @MinValue
|
||||
WHILE @Weight_Age <= @MaxValue
|
||||
BEGIN
|
||||
SET @Weight_CareerPlacings = @MinValue
|
||||
WHILE @Weight_CareerPlacings <= @MaxValue
|
||||
BEGIN
|
||||
SET @Weight_DryTrackStrikeRate = @MinValue
|
||||
WHILE @Weight_DryTrackStrikeRate <= @MaxValue
|
||||
BEGIN
|
||||
SET @Weight_ThisTrackStrikeRate = @MinValue
|
||||
WHILE @Weight_ThisTrackStrikeRate <= @MaxValue
|
||||
BEGIN
|
||||
SET @Weight_LastStartFinishPosition = @MinValue
|
||||
WHILE @Weight_LastStartFinishPosition <= @MaxValue
|
||||
BEGIN
|
||||
SET @Weight_WeightCarried = @MinValue
|
||||
WHILE @Weight_WeightCarried <= @MaxValue
|
||||
BEGIN
|
||||
SET @CombinazioneCorrente = @CombinazioneCorrente + 1
|
||||
|
||||
-- Calcolo in memoria: trova il cavallo con punteggio massimo per ogni corsa
|
||||
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
|
||||
SELECT
|
||||
Data,
|
||||
Meeting,
|
||||
Race,
|
||||
HorseName,
|
||||
(
|
||||
ISNULL(HandicapRating,0) * @Weight_HandicapRating +
|
||||
ISNULL(CareerWins,0) * @Weight_CareerWins +
|
||||
ISNULL(CareerStrikeRate,0) * @Weight_CareerStrikeRate +
|
||||
ISNULL(JockeyLast100StrikeRate,0) * @Weight_JockeyLast100StrikeRate +
|
||||
ISNULL(TrainerLast100StrikeRate,0) * @Weight_TrainerLast100StrikeRate +
|
||||
ISNULL(BestFixedOdds,0) * @Weight_BestFixedOdds +
|
||||
ISNULL(Age,0) * @Weight_Age +
|
||||
ISNULL(CareerPlacings,0) * @Weight_CareerPlacings +
|
||||
ISNULL(DryTrackStrikeRate,0) * @Weight_DryTrackStrikeRate +
|
||||
ISNULL(ThisTrackStrikeRate,0) * @Weight_ThisTrackStrikeRate +
|
||||
(CASE WHEN TRY_CAST(LastStartFinishPosition AS INT) > 0 THEN (1.0 / TRY_CAST(LastStartFinishPosition AS FLOAT)) ELSE 0 END) * @Weight_LastStartFinishPosition +
|
||||
ISNULL(WeightCarried,0) * @Weight_WeightCarried
|
||||
) AS Score,
|
||||
FinishResult
|
||||
INTO #Results
|
||||
FROM #AllHorses
|
||||
|
||||
-- Seleziona il cavallo con punteggio massimo per ogni corsa
|
||||
;WITH Ranked AS (
|
||||
SELECT *,
|
||||
ROW_NUMBER() OVER (PARTITION BY Data, Meeting, Race ORDER BY Score DESC) AS RankByScore
|
||||
FROM #Results
|
||||
)
|
||||
SELECT *
|
||||
INTO #TopResults
|
||||
FROM Ranked
|
||||
WHERE RankByScore = 1
|
||||
|
||||
-- Calcola le statistiche
|
||||
SELECT
|
||||
@CorrectPredictions = SUM(CASE WHEN ISNUMERIC(FinishResult) = 1 AND CAST(FinishResult AS INT) = 1 THEN 1 ELSE 0 END)
|
||||
FROM #TopResults
|
||||
|
||||
-- @TotalRaces già calcolato all'inizio
|
||||
|
||||
IF @TotalRaces > 0
|
||||
SET @WinPercentage = CAST(@CorrectPredictions AS DECIMAL(5,2)) * 100.0 / @TotalRaces
|
||||
ELSE
|
||||
SET @WinPercentage = 0
|
||||
|
||||
-- Aggiorna solo se la percentuale è migliore
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM PredictionScanResults
|
||||
WHERE SessionId = @SessionId
|
||||
AND WinPercentage < @WinPercentage
|
||||
)
|
||||
BEGIN
|
||||
UPDATE PredictionScanResults
|
||||
SET
|
||||
Weight_HandicapRating = @Weight_HandicapRating,
|
||||
Weight_CareerWins = @Weight_CareerWins,
|
||||
Weight_CareerStrikeRate = @Weight_CareerStrikeRate,
|
||||
Weight_JockeyLast100StrikeRate = @Weight_JockeyLast100StrikeRate,
|
||||
Weight_TrainerLast100StrikeRate = @Weight_TrainerLast100StrikeRate,
|
||||
Weight_BestFixedOdds = @Weight_BestFixedOdds,
|
||||
Weight_Age = @Weight_Age,
|
||||
Weight_CareerPlacings = @Weight_CareerPlacings,
|
||||
Weight_DryTrackStrikeRate = @Weight_DryTrackStrikeRate,
|
||||
Weight_ThisTrackStrikeRate = @Weight_ThisTrackStrikeRate,
|
||||
Weight_LastStartFinishPosition = @Weight_LastStartFinishPosition,
|
||||
Weight_WeightCarried = @Weight_WeightCarried,
|
||||
TotalRaces = @TotalRaces,
|
||||
CorrectPredictions = @CorrectPredictions,
|
||||
WinPercentage = @WinPercentage
|
||||
WHERE SessionId = @SessionId
|
||||
END
|
||||
|
||||
-- Output avanzamento
|
||||
PRINT CONCAT(
|
||||
'Combinazione ', @CombinazioneCorrente, '/', @CombinazioniTotali,
|
||||
' (', CAST((@CombinazioneCorrente * 100.0 / @CombinazioniTotali) AS DECIMAL(5,2)), '%) - ',
|
||||
'Pesi: ', @Weight_HandicapRating, ',', @Weight_CareerWins, ',', @Weight_CareerStrikeRate, ',',
|
||||
@Weight_JockeyLast100StrikeRate, ',', @Weight_TrainerLast100StrikeRate, ',', @Weight_BestFixedOdds, ',',
|
||||
@Weight_Age, ',', @Weight_CareerPlacings, ',', @Weight_DryTrackStrikeRate, ',', @Weight_ThisTrackStrikeRate, ',',
|
||||
@Weight_LastStartFinishPosition, ',', @Weight_WeightCarried,
|
||||
' - Win%: ', @WinPercentage
|
||||
)
|
||||
|
||||
DROP TABLE IF EXISTS #Results
|
||||
DROP TABLE IF EXISTS #TopResults
|
||||
|
||||
SET @Weight_WeightCarried = @Weight_WeightCarried + 1
|
||||
END
|
||||
SET @Weight_LastStartFinishPosition = @Weight_LastStartFinishPosition + 1
|
||||
END
|
||||
SET @Weight_ThisTrackStrikeRate = @Weight_ThisTrackStrikeRate + 1
|
||||
END
|
||||
SET @Weight_DryTrackStrikeRate = @Weight_DryTrackStrikeRate + 1
|
||||
END
|
||||
SET @Weight_CareerPlacings = @Weight_CareerPlacings + 1
|
||||
END
|
||||
SET @Weight_Age = @Weight_Age + 1
|
||||
END
|
||||
SET @Weight_BestFixedOdds = @Weight_BestFixedOdds + 1
|
||||
END
|
||||
SET @Weight_TrainerLast100StrikeRate = @Weight_TrainerLast100StrikeRate + 1
|
||||
END
|
||||
SET @Weight_JockeyLast100StrikeRate = @Weight_JockeyLast100StrikeRate + 1
|
||||
END
|
||||
SET @Weight_CareerStrikeRate = @Weight_CareerStrikeRate + 1
|
||||
END
|
||||
SET @Weight_CareerWins = @Weight_CareerWins + 1
|
||||
END
|
||||
SET @Weight_HandicapRating = @Weight_HandicapRating + 1
|
||||
END
|
||||
END
|
||||
40
HorseRacingPredictor/HorseRacingPredictor/UI/CardPanel.cs
Normal file
40
HorseRacingPredictor/HorseRacingPredictor/UI/CardPanel.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Pannello con angoli arrotondati e ombra simulata per stile card moderno
|
||||
/// </summary>
|
||||
internal class CardPanel : Panel
|
||||
{
|
||||
public int Radius { get; set; } = ModernTheme.CardRadius;
|
||||
|
||||
public CardPanel()
|
||||
{
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw, true);
|
||||
BackColor = Color.Transparent;
|
||||
Padding = new Padding(ModernTheme.CardPadding);
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
var g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
// Pulisci sfondo
|
||||
using (var bgBrush = new SolidBrush(Parent?.BackColor ?? ModernTheme.ContentBackground))
|
||||
g.FillRectangle(bgBrush, ClientRectangle);
|
||||
|
||||
var cardRect = new Rectangle(0, 0, Width - 2, Height - 2);
|
||||
using (var path = ModernTheme.GetRoundedRectPath(cardRect, Radius))
|
||||
{
|
||||
using (var brush = new SolidBrush(ModernTheme.CardBackground))
|
||||
g.FillPath(brush, path);
|
||||
using (var pen = new Pen(ModernTheme.CardBorder, 1))
|
||||
g.DrawPath(pen, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Pulsante moderno con tema scuro e effetti hover
|
||||
/// </summary>
|
||||
public class ModernButton : Button
|
||||
{
|
||||
private bool isHovering = false;
|
||||
private Color normalColor = ModernTheme.Colors.AccentPrimary;
|
||||
private Color hoverColor = ModernTheme.Colors.AccentSecondary;
|
||||
private int borderRadius = ModernTheme.BorderRadius.Medium;
|
||||
|
||||
public ModernButton()
|
||||
{
|
||||
// Configurazione base
|
||||
FlatStyle = FlatStyle.Flat;
|
||||
FlatAppearance.BorderSize = 0;
|
||||
BackColor = normalColor;
|
||||
ForeColor = ModernTheme.Colors.TextPrimary;
|
||||
Font = ModernTheme.Fonts.ButtonFont;
|
||||
Cursor = Cursors.Hand;
|
||||
Size = new Size(100, 35);
|
||||
|
||||
// Abilita il double buffering per evitare flickering
|
||||
SetStyle(ControlStyles.UserPaint |
|
||||
ControlStyles.AllPaintingInWmPaint |
|
||||
ControlStyles.OptimizedDoubleBuffer, true);
|
||||
}
|
||||
|
||||
public Color NormalColor
|
||||
{
|
||||
get => normalColor;
|
||||
set
|
||||
{
|
||||
normalColor = value;
|
||||
if (!isHovering) BackColor = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Color HoverColor
|
||||
{
|
||||
get => hoverColor;
|
||||
set => hoverColor = value;
|
||||
}
|
||||
|
||||
public int BorderRadius
|
||||
{
|
||||
get => borderRadius;
|
||||
set
|
||||
{
|
||||
borderRadius = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(EventArgs e)
|
||||
{
|
||||
base.OnMouseEnter(e);
|
||||
isHovering = true;
|
||||
BackColor = hoverColor;
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(EventArgs e)
|
||||
{
|
||||
base.OnMouseLeave(e);
|
||||
isHovering = false;
|
||||
BackColor = normalColor;
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
// Disegna il background con bordi arrotondati
|
||||
using (GraphicsPath path = GetRoundedRectangle(ClientRectangle, borderRadius))
|
||||
{
|
||||
using (SolidBrush brush = new SolidBrush(BackColor))
|
||||
{
|
||||
e.Graphics.FillPath(brush, path);
|
||||
}
|
||||
}
|
||||
|
||||
// Disegna il testo centrato
|
||||
TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle,
|
||||
ForeColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
|
||||
}
|
||||
|
||||
private GraphicsPath GetRoundedRectangle(Rectangle rect, int radius)
|
||||
{
|
||||
GraphicsPath path = new GraphicsPath();
|
||||
int diameter = radius * 2;
|
||||
|
||||
path.AddArc(rect.X, rect.Y, diameter, diameter, 180, 90);
|
||||
path.AddArc(rect.Right - diameter, rect.Y, diameter, diameter, 270, 90);
|
||||
path.AddArc(rect.Right - diameter, rect.Bottom - diameter, diameter, diameter, 0, 90);
|
||||
path.AddArc(rect.X, rect.Bottom - diameter, diameter, diameter, 90, 90);
|
||||
path.CloseFigure();
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// DataGridView moderna con tema scuro
|
||||
/// </summary>
|
||||
public class ModernDataGridView : DataGridView
|
||||
{
|
||||
public ModernDataGridView()
|
||||
{
|
||||
// Configurazione base
|
||||
BackgroundColor = ModernTheme.Colors.PrimaryBackground;
|
||||
GridColor = ModernTheme.Colors.BorderPrimary;
|
||||
BorderStyle = BorderStyle.None;
|
||||
|
||||
// Colori delle celle
|
||||
DefaultCellStyle.BackColor = ModernTheme.Colors.GridRowEven;
|
||||
DefaultCellStyle.ForeColor = ModernTheme.Colors.TextPrimary;
|
||||
DefaultCellStyle.SelectionBackColor = ModernTheme.Colors.GridSelected;
|
||||
DefaultCellStyle.SelectionForeColor = ModernTheme.Colors.TextPrimary;
|
||||
DefaultCellStyle.Font = ModernTheme.Fonts.RegularFont;
|
||||
|
||||
// Alternating row color
|
||||
AlternatingRowsDefaultCellStyle.BackColor = ModernTheme.Colors.GridRowOdd;
|
||||
AlternatingRowsDefaultCellStyle.ForeColor = ModernTheme.Colors.TextPrimary;
|
||||
|
||||
// Header
|
||||
ColumnHeadersDefaultCellStyle.BackColor = ModernTheme.Colors.GridHeader;
|
||||
ColumnHeadersDefaultCellStyle.ForeColor = ModernTheme.Colors.TextPrimary;
|
||||
ColumnHeadersDefaultCellStyle.Font = ModernTheme.Fonts.SubtitleFont;
|
||||
ColumnHeadersDefaultCellStyle.SelectionBackColor = ModernTheme.Colors.GridHeader;
|
||||
ColumnHeadersDefaultCellStyle.SelectionForeColor = ModernTheme.Colors.TextPrimary;
|
||||
ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single;
|
||||
ColumnHeadersHeight = 35;
|
||||
|
||||
// Row
|
||||
RowHeadersDefaultCellStyle.BackColor = ModernTheme.Colors.GridHeader;
|
||||
RowHeadersDefaultCellStyle.ForeColor = ModernTheme.Colors.TextPrimary;
|
||||
RowHeadersDefaultCellStyle.SelectionBackColor = ModernTheme.Colors.GridHeader;
|
||||
RowHeadersDefaultCellStyle.SelectionForeColor = ModernTheme.Colors.TextPrimary;
|
||||
RowHeadersVisible = false;
|
||||
|
||||
// Altre impostazioni
|
||||
EnableHeadersVisualStyles = false;
|
||||
AllowUserToAddRows = false;
|
||||
AllowUserToDeleteRows = false;
|
||||
ReadOnly = true;
|
||||
SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
MultiSelect = false;
|
||||
AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
|
||||
RowTemplate.Height = 30;
|
||||
|
||||
// Abilita il double buffering per evitare flickering
|
||||
DoubleBuffered = true;
|
||||
|
||||
// Eventi per l'hover effect
|
||||
CellMouseEnter += OnCellMouseEnterHandler;
|
||||
CellMouseLeave += OnCellMouseLeaveHandler;
|
||||
}
|
||||
|
||||
private void OnCellMouseEnterHandler(object sender, DataGridViewCellEventArgs e)
|
||||
{
|
||||
if (e.RowIndex >= 0)
|
||||
{
|
||||
Rows[e.RowIndex].DefaultCellStyle.BackColor = ModernTheme.Colors.GridHover;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCellMouseLeaveHandler(object sender, DataGridViewCellEventArgs e)
|
||||
{
|
||||
if (e.RowIndex >= 0)
|
||||
{
|
||||
// Ripristina il colore originale in base all'indice della riga
|
||||
if (e.RowIndex % 2 == 0)
|
||||
Rows[e.RowIndex].DefaultCellStyle.BackColor = ModernTheme.Colors.GridRowEven;
|
||||
else
|
||||
Rows[e.RowIndex].DefaultCellStyle.BackColor = ModernTheme.Colors.GridRowOdd;
|
||||
}
|
||||
}
|
||||
|
||||
public void HighlightWinnerRows()
|
||||
{
|
||||
if (Columns.Contains("Risultato Reale"))
|
||||
{
|
||||
foreach (DataGridViewRow row in Rows)
|
||||
{
|
||||
if (row.Cells["Risultato Reale"].Value != null &&
|
||||
row.Cells["Risultato Reale"].Value.ToString() == "1")
|
||||
{
|
||||
row.DefaultCellStyle.BackColor = ModernTheme.Colors.StatusWin;
|
||||
}
|
||||
else if (row.Cells["Risultato Reale"].Value != null &&
|
||||
int.TryParse(row.Cells["Risultato Reale"].Value.ToString(), out int pos) && pos <= 3)
|
||||
{
|
||||
row.DefaultCellStyle.BackColor = ModernTheme.Colors.StatusPlace;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// DateTimePicker moderna con tema scuro
|
||||
/// Nota: Il controllo DateTimePicker di WinForms non supporta completamente il custom painting,
|
||||
/// quindi alcuni elementi potrebbero mantenere lo stile di sistema
|
||||
/// </summary>
|
||||
public class ModernDateTimePicker : DateTimePicker
|
||||
{
|
||||
public ModernDateTimePicker()
|
||||
{
|
||||
// Configurazione base
|
||||
Font = ModernTheme.Fonts.RegularFont;
|
||||
Format = DateTimePickerFormat.Custom;
|
||||
CustomFormat = "dd/MM/yyyy";
|
||||
|
||||
// Imposta i colori per il calendario
|
||||
CalendarMonthBackground = ModernTheme.Colors.TertiaryBackground;
|
||||
CalendarForeColor = ModernTheme.Colors.TextPrimary;
|
||||
CalendarTitleBackColor = ModernTheme.Colors.SecondaryBackground;
|
||||
CalendarTitleForeColor = ModernTheme.Colors.TextPrimary;
|
||||
CalendarTrailingForeColor = ModernTheme.Colors.TextDisabled;
|
||||
|
||||
// Dimensioni
|
||||
Height = 30;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposta il formato lungo (con ora)
|
||||
/// </summary>
|
||||
public void SetLongFormat()
|
||||
{
|
||||
CustomFormat = "dd/MM/yyyy HH:mm";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposta il formato corto (solo data)
|
||||
/// </summary>
|
||||
public void SetShortFormat()
|
||||
{
|
||||
CustomFormat = "dd/MM/yyyy";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Label moderna con tema scuro e testo ben visibile
|
||||
/// </summary>
|
||||
public class ModernLabel : Label
|
||||
{
|
||||
public ModernLabel()
|
||||
{
|
||||
// Configurazione base per visibilità su sfondo scuro
|
||||
ForeColor = ModernTheme.Colors.TextSecondary;
|
||||
Font = ModernTheme.Fonts.RegularFont;
|
||||
BackColor = Color.Transparent;
|
||||
AutoSize = true;
|
||||
|
||||
// Abilita anti-aliasing per testo più leggibile
|
||||
SetStyle(ControlStyles.OptimizedDoubleBuffer |
|
||||
ControlStyles.AllPaintingInWmPaint, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposta lo stile del label come titolo
|
||||
/// </summary>
|
||||
public void SetAsTitleLabel()
|
||||
{
|
||||
Font = ModernTheme.Fonts.TitleFont;
|
||||
ForeColor = ModernTheme.Colors.TextPrimary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposta lo stile del label come sottotitolo
|
||||
/// </summary>
|
||||
public void SetAsSubtitleLabel()
|
||||
{
|
||||
Font = ModernTheme.Fonts.SubtitleFont;
|
||||
ForeColor = ModernTheme.Colors.TextPrimary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposta lo stile del label come testo di stato
|
||||
/// </summary>
|
||||
public void SetAsStatusLabel()
|
||||
{
|
||||
Font = ModernTheme.Fonts.RegularFont;
|
||||
ForeColor = ModernTheme.Colors.TextSecondary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposta lo stile del label come testo di successo
|
||||
/// </summary>
|
||||
public void SetAsSuccessLabel()
|
||||
{
|
||||
Font = ModernTheme.Fonts.RegularFont;
|
||||
ForeColor = ModernTheme.Colors.AccentSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposta lo stile del label come testo di errore
|
||||
/// </summary>
|
||||
public void SetAsErrorLabel()
|
||||
{
|
||||
Font = ModernTheme.Fonts.RegularFont;
|
||||
ForeColor = ModernTheme.Colors.AccentError;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposta lo stile del label come testo di warning
|
||||
/// </summary>
|
||||
public void SetAsWarningLabel()
|
||||
{
|
||||
Font = ModernTheme.Fonts.RegularFont;
|
||||
ForeColor = ModernTheme.Colors.AccentWarning;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Panel moderno con tema scuro e bordi arrotondati
|
||||
/// </summary>
|
||||
public class ModernPanel : Panel
|
||||
{
|
||||
private int borderRadius = ModernTheme.BorderRadius.Medium;
|
||||
private Color borderColor = ModernTheme.Colors.BorderPrimary;
|
||||
private int borderWidth = 1;
|
||||
|
||||
public ModernPanel()
|
||||
{
|
||||
BackColor = ModernTheme.Colors.SecondaryBackground;
|
||||
|
||||
// Abilita il double buffering
|
||||
SetStyle(ControlStyles.UserPaint |
|
||||
ControlStyles.AllPaintingInWmPaint |
|
||||
ControlStyles.OptimizedDoubleBuffer |
|
||||
ControlStyles.ResizeRedraw, true);
|
||||
}
|
||||
|
||||
public int BorderRadius
|
||||
{
|
||||
get => borderRadius;
|
||||
set
|
||||
{
|
||||
borderRadius = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public Color BorderColor
|
||||
{
|
||||
get => borderColor;
|
||||
set
|
||||
{
|
||||
borderColor = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public int BorderWidth
|
||||
{
|
||||
get => borderWidth;
|
||||
set
|
||||
{
|
||||
borderWidth = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
base.OnPaint(e);
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
// Disegna il background con bordi arrotondati
|
||||
using (GraphicsPath path = GetRoundedRectangle(ClientRectangle, borderRadius))
|
||||
{
|
||||
// Background
|
||||
using (SolidBrush brush = new SolidBrush(BackColor))
|
||||
{
|
||||
e.Graphics.FillPath(brush, path);
|
||||
}
|
||||
|
||||
// Bordo
|
||||
if (borderWidth > 0)
|
||||
{
|
||||
using (Pen pen = new Pen(borderColor, borderWidth))
|
||||
{
|
||||
e.Graphics.DrawPath(pen, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GraphicsPath GetRoundedRectangle(Rectangle rect, int radius)
|
||||
{
|
||||
GraphicsPath path = new GraphicsPath();
|
||||
int diameter = radius * 2;
|
||||
|
||||
rect.Inflate(-borderWidth / 2, -borderWidth / 2);
|
||||
|
||||
path.AddArc(rect.X, rect.Y, diameter, diameter, 180, 90);
|
||||
path.AddArc(rect.Right - diameter, rect.Y, diameter, diameter, 270, 90);
|
||||
path.AddArc(rect.Right - diameter, rect.Bottom - diameter, diameter, diameter, 0, 90);
|
||||
path.AddArc(rect.X, rect.Bottom - diameter, diameter, diameter, 90, 90);
|
||||
path.CloseFigure();
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// ProgressBar moderna con tema scuro e animazioni fluide
|
||||
/// </summary>
|
||||
public class ModernProgressBar : ProgressBar
|
||||
{
|
||||
public ModernProgressBar()
|
||||
{
|
||||
// Configurazione base
|
||||
SetStyle(ControlStyles.UserPaint |
|
||||
ControlStyles.AllPaintingInWmPaint |
|
||||
ControlStyles.OptimizedDoubleBuffer, true);
|
||||
|
||||
Height = 6;
|
||||
BackColor = ModernTheme.Colors.TertiaryBackground;
|
||||
ForeColor = ModernTheme.Colors.AccentPrimary;
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
Rectangle rect = ClientRectangle;
|
||||
Graphics g = e.Graphics;
|
||||
|
||||
// Disegna il background
|
||||
using (SolidBrush brush = new SolidBrush(ModernTheme.Colors.TertiaryBackground))
|
||||
{
|
||||
g.FillRectangle(brush, rect);
|
||||
}
|
||||
|
||||
// Calcola la larghezza del progresso
|
||||
int progressWidth = (int)(rect.Width * ((double)Value / Maximum));
|
||||
|
||||
// Disegna la barra di progresso
|
||||
if (progressWidth > 0)
|
||||
{
|
||||
Rectangle progressRect = new Rectangle(rect.X, rect.Y, progressWidth, rect.Height);
|
||||
using (SolidBrush brush = new SolidBrush(ForeColor))
|
||||
{
|
||||
g.FillRectangle(brush, progressRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetProgressColor(Color color)
|
||||
{
|
||||
ForeColor = color;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// TabControl moderna con tema scuro
|
||||
/// </summary>
|
||||
public class ModernTabControl : TabControl
|
||||
{
|
||||
public ModernTabControl()
|
||||
{
|
||||
SetStyle(ControlStyles.UserPaint |
|
||||
ControlStyles.AllPaintingInWmPaint |
|
||||
ControlStyles.OptimizedDoubleBuffer |
|
||||
ControlStyles.ResizeRedraw, true);
|
||||
|
||||
DrawMode = TabDrawMode.OwnerDrawFixed;
|
||||
SizeMode = TabSizeMode.Fixed;
|
||||
ItemSize = new Size(120, 40);
|
||||
Padding = new Point(20, 0);
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
e.Graphics.Clear(ModernTheme.Colors.PrimaryBackground);
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
// Disegna il background del tab panel
|
||||
Rectangle tabPanelRect = new Rectangle(0, ItemSize.Height, Width, Height - ItemSize.Height);
|
||||
using (SolidBrush brush = new SolidBrush(ModernTheme.Colors.SecondaryBackground))
|
||||
{
|
||||
e.Graphics.FillRectangle(brush, tabPanelRect);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDrawItem(DrawItemEventArgs e)
|
||||
{
|
||||
Graphics g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
// Get tab rectangle
|
||||
Rectangle tabRect = GetTabRect(e.Index);
|
||||
|
||||
bool isSelected = (e.Index == SelectedIndex);
|
||||
|
||||
// Disegna il background della tab
|
||||
Color backColor = isSelected ? ModernTheme.Colors.SecondaryBackground : ModernTheme.Colors.PrimaryBackground;
|
||||
using (SolidBrush brush = new SolidBrush(backColor))
|
||||
{
|
||||
g.FillRectangle(brush, tabRect);
|
||||
}
|
||||
|
||||
// Disegna la linea di selezione in alto
|
||||
if (isSelected)
|
||||
{
|
||||
Rectangle accentRect = new Rectangle(tabRect.X, tabRect.Y, tabRect.Width, 3);
|
||||
using (SolidBrush brush = new SolidBrush(ModernTheme.Colors.AccentPrimary))
|
||||
{
|
||||
g.FillRectangle(brush, accentRect);
|
||||
}
|
||||
}
|
||||
|
||||
// Disegna il testo della tab
|
||||
string tabText = TabPages[e.Index].Text;
|
||||
Color textColor = isSelected ? ModernTheme.Colors.TextPrimary : ModernTheme.Colors.TextSecondary;
|
||||
Font tabFont = isSelected ? ModernTheme.Fonts.SubtitleFont : ModernTheme.Fonts.RegularFont;
|
||||
|
||||
StringFormat sf = new StringFormat
|
||||
{
|
||||
Alignment = StringAlignment.Center,
|
||||
LineAlignment = StringAlignment.Center
|
||||
};
|
||||
|
||||
using (SolidBrush brush = new SolidBrush(textColor))
|
||||
{
|
||||
g.DrawString(tabText, tabFont, brush, tabRect, sf);
|
||||
}
|
||||
|
||||
// Disegna il bordo tra le tabs
|
||||
if (e.Index < TabCount - 1)
|
||||
{
|
||||
using (Pen pen = new Pen(ModernTheme.Colors.BorderPrimary, 1))
|
||||
{
|
||||
g.DrawLine(pen, tabRect.Right, tabRect.Top + 10, tabRect.Right, tabRect.Bottom - 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSelectedIndexChanged(EventArgs e)
|
||||
{
|
||||
base.OnSelectedIndexChanged(e);
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// TextBox moderno con tema scuro e bordi arrotondati
|
||||
/// </summary>
|
||||
public class ModernTextBox : TextBox
|
||||
{
|
||||
private Color borderColor = ModernTheme.Colors.BorderPrimary;
|
||||
private Color focusBorderColor = ModernTheme.Colors.BorderAccent;
|
||||
private bool isFocused = false;
|
||||
private int borderRadius = ModernTheme.BorderRadius.Medium;
|
||||
|
||||
public ModernTextBox()
|
||||
{
|
||||
// Configurazione base
|
||||
BorderStyle = BorderStyle.None;
|
||||
BackColor = ModernTheme.Colors.TertiaryBackground;
|
||||
ForeColor = ModernTheme.Colors.TextPrimary;
|
||||
Font = ModernTheme.Fonts.RegularFont;
|
||||
Padding = new Padding(8, 8, 8, 8);
|
||||
|
||||
// Abilita il double buffering
|
||||
SetStyle(ControlStyles.UserPaint |
|
||||
ControlStyles.AllPaintingInWmPaint |
|
||||
ControlStyles.OptimizedDoubleBuffer, true);
|
||||
}
|
||||
|
||||
public Color BorderColor
|
||||
{
|
||||
get => borderColor;
|
||||
set
|
||||
{
|
||||
borderColor = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public Color FocusBorderColor
|
||||
{
|
||||
get => focusBorderColor;
|
||||
set
|
||||
{
|
||||
focusBorderColor = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public int BorderRadius
|
||||
{
|
||||
get => borderRadius;
|
||||
set
|
||||
{
|
||||
borderRadius = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnEnter(EventArgs e)
|
||||
{
|
||||
base.OnEnter(e);
|
||||
isFocused = true;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnLeave(EventArgs e)
|
||||
{
|
||||
base.OnLeave(e);
|
||||
isFocused = false;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnReadOnlyChanged(EventArgs e)
|
||||
{
|
||||
base.OnReadOnlyChanged(e);
|
||||
// Cambia il colore del testo per i campi read-only
|
||||
if (ReadOnly)
|
||||
{
|
||||
ForeColor = ModernTheme.Colors.TextSecondary;
|
||||
BackColor = ModernTheme.Colors.SecondaryBackground;
|
||||
}
|
||||
else
|
||||
{
|
||||
ForeColor = ModernTheme.Colors.TextPrimary;
|
||||
BackColor = ModernTheme.Colors.TertiaryBackground;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
// Disegna il background
|
||||
using (GraphicsPath path = GetRoundedRectangle(ClientRectangle, borderRadius))
|
||||
{
|
||||
using (SolidBrush brush = new SolidBrush(BackColor))
|
||||
{
|
||||
e.Graphics.FillPath(brush, path);
|
||||
}
|
||||
|
||||
// Disegna il bordo
|
||||
Color currentBorderColor = isFocused ? focusBorderColor : borderColor;
|
||||
using (Pen pen = new Pen(currentBorderColor, 1.5f))
|
||||
{
|
||||
e.Graphics.DrawPath(pen, path);
|
||||
}
|
||||
}
|
||||
|
||||
// Disegna il testo
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
TextRenderer.DrawText(e.Graphics, Text, Font,
|
||||
new Rectangle(8, 0, Width - 16, Height),
|
||||
ForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
|
||||
}
|
||||
}
|
||||
|
||||
private GraphicsPath GetRoundedRectangle(Rectangle rect, int radius)
|
||||
{
|
||||
GraphicsPath path = new GraphicsPath();
|
||||
int diameter = radius * 2;
|
||||
|
||||
rect.Inflate(-1, -1);
|
||||
|
||||
path.AddArc(rect.X, rect.Y, diameter, diameter, 180, 90);
|
||||
path.AddArc(rect.Right - diameter, rect.Y, diameter, diameter, 270, 90);
|
||||
path.AddArc(rect.Right - diameter, rect.Bottom - diameter, diameter, diameter, 0, 90);
|
||||
path.AddArc(rect.X, rect.Bottom - diameter, diameter, diameter, 90, 90);
|
||||
path.CloseFigure();
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
89
HorseRacingPredictor/HorseRacingPredictor/UI/ModernButton.cs
Normal file
89
HorseRacingPredictor/HorseRacingPredictor/UI/ModernButton.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Pulsante con stile moderno (arrotondato, con effetti hover)
|
||||
/// </summary>
|
||||
internal class ModernButton : Button
|
||||
{
|
||||
private bool _isHovered;
|
||||
private bool _isPressed;
|
||||
private Color _accentColor;
|
||||
|
||||
public Color AccentColor
|
||||
{
|
||||
get => _accentColor;
|
||||
set { _accentColor = value; Invalidate(); }
|
||||
}
|
||||
|
||||
public bool IsPrimary { get; set; } = true;
|
||||
|
||||
public ModernButton()
|
||||
{
|
||||
_accentColor = ModernTheme.PrimaryColor;
|
||||
FlatStyle = FlatStyle.Flat;
|
||||
FlatAppearance.BorderSize = 0;
|
||||
Font = new Font("Segoe UI Semibold", 10F);
|
||||
ForeColor = Color.White;
|
||||
Cursor = Cursors.Hand;
|
||||
Height = 36;
|
||||
MinimumSize = new Size(100, 36);
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.Opaque, true);
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
var g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
||||
|
||||
// Pulisci sfondo
|
||||
using (var bgBrush = new SolidBrush(Parent?.BackColor ?? ModernTheme.ContentBackground))
|
||||
g.FillRectangle(bgBrush, ClientRectangle);
|
||||
|
||||
var rect = new Rectangle(0, 0, Width - 1, Height - 1);
|
||||
|
||||
Color bgColor;
|
||||
if (!Enabled)
|
||||
bgColor = Color.FromArgb(100, _accentColor);
|
||||
else if (_isPressed)
|
||||
bgColor = ControlPaint.Dark(_accentColor, 0.15f);
|
||||
else if (_isHovered)
|
||||
bgColor = ControlPaint.Light(_accentColor, 0.15f);
|
||||
else
|
||||
bgColor = _accentColor;
|
||||
|
||||
using (var path = ModernTheme.GetRoundedRectPath(rect, 6))
|
||||
{
|
||||
if (IsPrimary)
|
||||
{
|
||||
using (var brush = new SolidBrush(bgColor))
|
||||
g.FillPath(brush, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var brush = new SolidBrush(ModernTheme.CardBackground))
|
||||
g.FillPath(brush, path);
|
||||
using (var pen = new Pen(bgColor, 2))
|
||||
g.DrawPath(pen, path);
|
||||
}
|
||||
|
||||
var textColor = IsPrimary ? Color.FromArgb(24, 24, 37) : ModernTheme.TextPrimary;
|
||||
using (var textBrush = new SolidBrush(Enabled ? textColor : Color.FromArgb(80, textColor)))
|
||||
{
|
||||
var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
|
||||
g.DrawString(Text, Font, textBrush, rect, sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(EventArgs e) { _isHovered = true; Invalidate(); base.OnMouseEnter(e); }
|
||||
protected override void OnMouseLeave(EventArgs e) { _isHovered = false; _isPressed = false; Invalidate(); base.OnMouseLeave(e); }
|
||||
protected override void OnMouseDown(MouseEventArgs e) { _isPressed = true; Invalidate(); base.OnMouseDown(e); }
|
||||
protected override void OnMouseUp(MouseEventArgs e) { _isPressed = false; Invalidate(); base.OnMouseUp(e); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// ProgressBar moderna con stile piatto e bordi arrotondati
|
||||
/// </summary>
|
||||
internal class ModernProgressBar : ProgressBar
|
||||
{
|
||||
public Color BarColor { get; set; } = ModernTheme.PrimaryColor;
|
||||
public Color TrackColor { get; set; } = Color.FromArgb(49, 50, 68);
|
||||
|
||||
public ModernProgressBar()
|
||||
{
|
||||
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer | ControlStyles.Opaque, true);
|
||||
Height = 8;
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
var g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
// Pulisci sfondo
|
||||
using (var bgBrush = new SolidBrush(Parent?.BackColor ?? ModernTheme.ContentBackground))
|
||||
g.FillRectangle(bgBrush, ClientRectangle);
|
||||
|
||||
var rect = new Rectangle(0, 0, Width - 1, Height - 1);
|
||||
using (var path = ModernTheme.GetRoundedRectPath(rect, Height / 2))
|
||||
using (var brush = new SolidBrush(TrackColor))
|
||||
{
|
||||
g.FillPath(brush, path);
|
||||
}
|
||||
|
||||
if (Maximum > Minimum && Value > Minimum)
|
||||
{
|
||||
float fraction = (float)(Value - Minimum) / (Maximum - Minimum);
|
||||
int fillWidth = (int)(rect.Width * fraction);
|
||||
if (fillWidth > 4)
|
||||
{
|
||||
var fillRect = new Rectangle(0, 0, fillWidth, Height - 1);
|
||||
using (var path = ModernTheme.GetRoundedRectPath(fillRect, Height / 2))
|
||||
using (var brush = new LinearGradientBrush(fillRect, BarColor, ControlPaint.Light(BarColor, 0.3f), LinearGradientMode.Horizontal))
|
||||
{
|
||||
g.FillPath(brush, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
115
HorseRacingPredictor/HorseRacingPredictor/UI/ModernTheme.cs
Normal file
115
HorseRacingPredictor/HorseRacingPredictor/UI/ModernTheme.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Tema grafico moderno scuro per l'applicazione
|
||||
/// </summary>
|
||||
internal static class ModernTheme
|
||||
{
|
||||
// Palette colori — DARK THEME
|
||||
public static readonly Color SidebarBackground = Color.FromArgb(24, 24, 37);
|
||||
public static readonly Color SidebarHover = Color.FromArgb(40, 40, 58);
|
||||
public static readonly Color SidebarActive = Color.FromArgb(137, 180, 250);
|
||||
public static readonly Color SidebarText = Color.FromArgb(186, 194, 222);
|
||||
public static readonly Color SidebarActiveText = Color.FromArgb(24, 24, 37);
|
||||
|
||||
public static readonly Color ContentBackground = Color.FromArgb(30, 30, 46);
|
||||
public static readonly Color CardBackground = Color.FromArgb(40, 42, 58);
|
||||
public static readonly Color CardBorder = Color.FromArgb(55, 57, 78);
|
||||
public static readonly Color HeaderBackground = Color.FromArgb(24, 24, 37);
|
||||
|
||||
public static readonly Color PrimaryColor = Color.FromArgb(137, 180, 250);
|
||||
public static readonly Color PrimaryDark = Color.FromArgb(116, 155, 220);
|
||||
public static readonly Color SuccessColor = Color.FromArgb(166, 218, 149);
|
||||
public static readonly Color WarningColor = Color.FromArgb(249, 226, 175);
|
||||
public static readonly Color DangerColor = Color.FromArgb(243, 139, 168);
|
||||
public static readonly Color TextPrimary = Color.FromArgb(205, 214, 244);
|
||||
public static readonly Color TextSecondary = Color.FromArgb(147, 153, 178);
|
||||
|
||||
public static readonly Color InputBackground = Color.FromArgb(49, 50, 68);
|
||||
public static readonly Color InputBorder = Color.FromArgb(69, 71, 90);
|
||||
public static readonly Color InputText = Color.FromArgb(205, 214, 244);
|
||||
|
||||
// Font
|
||||
public static readonly Font TitleFont = new Font("Segoe UI Semibold", 16F);
|
||||
public static readonly Font SubtitleFont = new Font("Segoe UI Semibold", 12F);
|
||||
public static readonly Font BodyFont = new Font("Segoe UI", 10F);
|
||||
public static readonly Font SmallFont = new Font("Segoe UI", 9F);
|
||||
public static readonly Font NavFont = new Font("Segoe UI Semibold", 11F);
|
||||
|
||||
// Dimensioni
|
||||
public const int SidebarWidth = 200;
|
||||
public const int CardRadius = 8;
|
||||
public const int CardPadding = 16;
|
||||
|
||||
/// <summary>
|
||||
/// Applica lo stile moderno scuro a un DataGridView
|
||||
/// </summary>
|
||||
public static void StyleDataGridView(DataGridView grid)
|
||||
{
|
||||
grid.BorderStyle = BorderStyle.None;
|
||||
grid.BackgroundColor = CardBackground;
|
||||
grid.GridColor = CardBorder;
|
||||
grid.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal;
|
||||
|
||||
grid.EnableHeadersVisualStyles = false;
|
||||
grid.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.None;
|
||||
grid.ColumnHeadersDefaultCellStyle = new DataGridViewCellStyle
|
||||
{
|
||||
BackColor = Color.FromArgb(35, 36, 52),
|
||||
ForeColor = PrimaryColor,
|
||||
Font = new Font("Segoe UI Semibold", 10F),
|
||||
Padding = new Padding(8, 4, 8, 4),
|
||||
Alignment = DataGridViewContentAlignment.MiddleLeft
|
||||
};
|
||||
grid.ColumnHeadersHeight = 40;
|
||||
|
||||
grid.DefaultCellStyle = new DataGridViewCellStyle
|
||||
{
|
||||
BackColor = CardBackground,
|
||||
ForeColor = TextPrimary,
|
||||
Font = BodyFont,
|
||||
SelectionBackColor = Color.FromArgb(60, 63, 85),
|
||||
SelectionForeColor = PrimaryColor,
|
||||
Padding = new Padding(6, 3, 6, 3)
|
||||
};
|
||||
|
||||
grid.AlternatingRowsDefaultCellStyle = new DataGridViewCellStyle
|
||||
{
|
||||
BackColor = Color.FromArgb(45, 47, 64),
|
||||
ForeColor = TextPrimary,
|
||||
Font = BodyFont,
|
||||
SelectionBackColor = Color.FromArgb(60, 63, 85),
|
||||
SelectionForeColor = PrimaryColor,
|
||||
Padding = new Padding(6, 3, 6, 3)
|
||||
};
|
||||
|
||||
grid.RowHeadersVisible = false;
|
||||
grid.RowTemplate.Height = 36;
|
||||
grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
|
||||
grid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
grid.ReadOnly = true;
|
||||
grid.AllowUserToAddRows = false;
|
||||
grid.AllowUserToDeleteRows = false;
|
||||
grid.AllowUserToResizeRows = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disegna un rettangolo arrotondato
|
||||
/// </summary>
|
||||
public static GraphicsPath GetRoundedRectPath(Rectangle rect, int radius)
|
||||
{
|
||||
var path = new GraphicsPath();
|
||||
int d = radius * 2;
|
||||
path.AddArc(rect.X, rect.Y, d, d, 180, 90);
|
||||
path.AddArc(rect.Right - d, rect.Y, d, d, 270, 90);
|
||||
path.AddArc(rect.Right - d, rect.Bottom - d, d, d, 0, 90);
|
||||
path.AddArc(rect.X, rect.Bottom - d, d, d, 90, 90);
|
||||
path.CloseFigure();
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
116
HorseRacingPredictor/HorseRacingPredictor/UI/NavButton.cs
Normal file
116
HorseRacingPredictor/HorseRacingPredictor/UI/NavButton.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BettingPredictor.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Pulsante di navigazione per la sidebar
|
||||
/// </summary>
|
||||
internal class NavButton : Button
|
||||
{
|
||||
private bool _isActive;
|
||||
private bool _isHovered;
|
||||
private readonly string _icon;
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => _isActive;
|
||||
set { _isActive = value; Invalidate(); }
|
||||
}
|
||||
|
||||
public NavButton(string text, string icon)
|
||||
{
|
||||
_icon = icon;
|
||||
Text = text;
|
||||
FlatStyle = FlatStyle.Flat;
|
||||
FlatAppearance.BorderSize = 0;
|
||||
FlatAppearance.MouseOverBackColor = Color.Transparent;
|
||||
FlatAppearance.MouseDownBackColor = Color.Transparent;
|
||||
Font = ModernTheme.NavFont;
|
||||
ForeColor = ModernTheme.SidebarText;
|
||||
BackColor = ModernTheme.SidebarBackground;
|
||||
Cursor = Cursors.Hand;
|
||||
Height = 44;
|
||||
Dock = DockStyle.Top;
|
||||
Padding = new Padding(0);
|
||||
Margin = new Padding(0);
|
||||
SetStyle(
|
||||
ControlStyles.AllPaintingInWmPaint |
|
||||
ControlStyles.UserPaint |
|
||||
ControlStyles.DoubleBuffer |
|
||||
ControlStyles.Opaque, true);
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
var g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
||||
|
||||
var rect = ClientRectangle;
|
||||
|
||||
// Sfondo pieno sidebar
|
||||
using (var bg = new SolidBrush(ModernTheme.SidebarBackground))
|
||||
g.FillRectangle(bg, rect);
|
||||
|
||||
// Stato attivo: rettangolo arrotondato + indicatore
|
||||
if (_isActive)
|
||||
{
|
||||
var activeRect = new Rectangle(8, 4, rect.Width - 16, rect.Height - 8);
|
||||
using (var path = ModernTheme.GetRoundedRectPath(activeRect, 6))
|
||||
using (var brush = new SolidBrush(ModernTheme.SidebarActive))
|
||||
g.FillPath(brush, path);
|
||||
|
||||
using (var bar = new SolidBrush(ModernTheme.SidebarActive))
|
||||
g.FillRectangle(bar, 0, 10, 3, rect.Height - 20);
|
||||
}
|
||||
// Stato hover (solo se non attivo)
|
||||
else if (_isHovered)
|
||||
{
|
||||
var hoverRect = new Rectangle(8, 4, rect.Width - 16, rect.Height - 8);
|
||||
using (var path = ModernTheme.GetRoundedRectPath(hoverRect, 6))
|
||||
using (var brush = new SolidBrush(ModernTheme.SidebarHover))
|
||||
g.FillPath(brush, path);
|
||||
}
|
||||
|
||||
// Colori testo/icona
|
||||
var fg = _isActive ? ModernTheme.SidebarActiveText : ModernTheme.SidebarText;
|
||||
|
||||
// Icona
|
||||
using (var iconFont = new Font("Segoe UI", 11F, FontStyle.Bold))
|
||||
using (var brush = new SolidBrush(fg))
|
||||
{
|
||||
var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
|
||||
g.DrawString(_icon, iconFont, brush, new RectangleF(14, 0, 28, rect.Height), sf);
|
||||
}
|
||||
|
||||
// Testo
|
||||
using (var brush = new SolidBrush(fg))
|
||||
{
|
||||
var sf = new StringFormat
|
||||
{
|
||||
Alignment = StringAlignment.Near,
|
||||
LineAlignment = StringAlignment.Center,
|
||||
FormatFlags = StringFormatFlags.NoWrap
|
||||
};
|
||||
g.DrawString(Text, Font, brush, new RectangleF(46, 0, rect.Width - 54, rect.Height), sf);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(EventArgs e)
|
||||
{
|
||||
_isHovered = true;
|
||||
Invalidate();
|
||||
base.OnMouseEnter(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(EventArgs e)
|
||||
{
|
||||
_isHovered = false;
|
||||
Invalidate();
|
||||
base.OnMouseLeave(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace HorseRacingPredictor.VirtualFootball
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single virtual football match result displayed in the results panel.
|
||||
/// </summary>
|
||||
public class VirtualMatch
|
||||
{
|
||||
public string Time { get; set; }
|
||||
public string Home { get; set; }
|
||||
public int HomeGoals { get; set; }
|
||||
public int AwayGoals { get; set; }
|
||||
public string Away { get; set; }
|
||||
|
||||
public string Score => $"{HomeGoals} - {AwayGoals}";
|
||||
|
||||
/// <summary>1, X, or 2</summary>
|
||||
public string Outcome
|
||||
{
|
||||
get
|
||||
{
|
||||
if (HomeGoals > AwayGoals) return "1";
|
||||
if (HomeGoals < AwayGoals) return "2";
|
||||
return "X";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Row background colour: green for draw, red for 1/2.</summary>
|
||||
public string RowColor => Outcome == "X" ? "#2A4A3A" : "#4A2A2A";
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="CsvHelper" version="33.0.1" targetFramework="net481" />
|
||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="10.0.0-preview.4.25258.110" targetFramework="net481" />
|
||||
<package id="CsvHelper" version="33.1.0" targetFramework="net481" />
|
||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="10.0.0-rc.1.25451.107" targetFramework="net481" />
|
||||
<package id="Microsoft.Bcl.HashCode" version="6.0.0" targetFramework="net481" />
|
||||
<package id="Microsoft.Bcl.Numerics" version="10.0.0-preview.4.25258.110" targetFramework="net481" />
|
||||
<package id="Microsoft.Bcl.Numerics" version="10.0.0-rc.1.25451.107" targetFramework="net481" />
|
||||
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net481" />
|
||||
<package id="Microsoft.ML" version="5.0.0-preview.1.25127.4" targetFramework="net481" />
|
||||
<package id="Microsoft.ML.CpuMath" version="5.0.0-preview.1.25127.4" targetFramework="net481" />
|
||||
<package id="Microsoft.ML.DataView" version="5.0.0-preview.1.25127.4" targetFramework="net481" />
|
||||
<package id="Microsoft.ML.FastTree" version="5.0.0-preview.1.25127.4" targetFramework="net481" />
|
||||
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net481" />
|
||||
<package id="Microsoft.ML" version="5.0.0-preview.25503.2" targetFramework="net481" />
|
||||
<package id="Microsoft.ML.CpuMath" version="5.0.0-preview.25503.2" targetFramework="net481" />
|
||||
<package id="Microsoft.ML.DataView" version="5.0.0-preview.25503.2" targetFramework="net481" />
|
||||
<package id="Microsoft.ML.FastTree" version="5.0.0-preview.25503.2" targetFramework="net481" />
|
||||
<package id="Microsoft.Web.WebView2" version="1.0.3800.47" targetFramework="net481" />
|
||||
<package id="Newtonsoft.Json" version="13.0.4" targetFramework="net481" />
|
||||
<package id="RestSharp" version="112.1.1-alpha.0.4" targetFramework="net481" />
|
||||
<package id="System.Buffers" version="4.6.1" targetFramework="net481" />
|
||||
<package id="System.CodeDom" version="10.0.0-preview.4.25258.110" targetFramework="net481" />
|
||||
<package id="System.Collections.Immutable" version="10.0.0-preview.4.25258.110" targetFramework="net481" />
|
||||
<package id="System.CodeDom" version="10.0.0-rc.1.25451.107" targetFramework="net481" />
|
||||
<package id="System.Collections.Immutable" version="10.0.0-rc.1.25451.107" targetFramework="net481" />
|
||||
<package id="System.IO.Pipelines" version="10.0.0-rc.1.25451.107" targetFramework="net481" />
|
||||
<package id="System.Memory" version="4.6.3" targetFramework="net481" />
|
||||
<package id="System.Numerics.Tensors" version="10.0.0-preview.4.25258.110" targetFramework="net481" />
|
||||
<package id="System.Numerics.Tensors" version="10.0.0-rc.1.25451.107" targetFramework="net481" />
|
||||
<package id="System.Numerics.Vectors" version="4.6.1" targetFramework="net481" />
|
||||
<package id="System.Reflection.Emit.Lightweight" version="4.7.0" targetFramework="net481" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="6.1.2" targetFramework="net481" />
|
||||
<package id="System.Threading.Channels" version="10.0.0-preview.4.25258.110" targetFramework="net481" />
|
||||
<package id="System.Text.Encodings.Web" version="10.0.0-rc.1.25451.107" targetFramework="net481" />
|
||||
<package id="System.Text.Json" version="10.0.0-rc.1.25451.107" targetFramework="net481" />
|
||||
<package id="System.Threading.Channels" version="10.0.0-rc.1.25451.107" targetFramework="net481" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.6.3" targetFramework="net481" />
|
||||
<package id="System.ValueTuple" version="4.6.1" targetFramework="net481" />
|
||||
</packages>
|
||||
249
HorseRacingPredictor/Styles/GlobalStyles.xaml
Normal file
249
HorseRacingPredictor/Styles/GlobalStyles.xaml
Normal file
@@ -0,0 +1,249 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<!-- =========================================================
|
||||
CATPPUCCIN MOCHA PALETTE (shared)
|
||||
========================================================= -->
|
||||
<Color x:Key="CBase">#1E1E2E</Color>
|
||||
<Color x:Key="CMantle">#181825</Color>
|
||||
<Color x:Key="CCrust">#11111B</Color>
|
||||
<Color x:Key="CSurface0">#313244</Color>
|
||||
<Color x:Key="CSurface1">#45475A</Color>
|
||||
<Color x:Key="CSurface2">#585B70</Color>
|
||||
<Color x:Key="COverlay0">#6C7086</Color>
|
||||
<Color x:Key="CText">#CDD6F4</Color>
|
||||
<Color x:Key="CSubtext0">#A6ADC8</Color>
|
||||
<Color x:Key="CSubtext1">#BAC2DE</Color>
|
||||
<Color x:Key="CBlue">#89B4FA</Color>
|
||||
<Color x:Key="CGreen">#A6E3A1</Color>
|
||||
<Color x:Key="CRed">#F38BA8</Color>
|
||||
<Color x:Key="CPeach">#FAB387</Color>
|
||||
<Color x:Key="CLavender">#B4BEFE</Color>
|
||||
|
||||
<SolidColorBrush x:Key="BrBase" Color="{StaticResource CBase}"/>
|
||||
<SolidColorBrush x:Key="BrMantle" Color="{StaticResource CMantle}"/>
|
||||
<SolidColorBrush x:Key="BrSurface0" Color="{StaticResource CSurface0}"/>
|
||||
<SolidColorBrush x:Key="BrSurface1" Color="{StaticResource CSurface1}"/>
|
||||
<SolidColorBrush x:Key="BrSurface2" Color="{StaticResource CSurface2}"/>
|
||||
<SolidColorBrush x:Key="BrOverlay0" Color="{StaticResource COverlay0}"/>
|
||||
<SolidColorBrush x:Key="BrText" Color="{StaticResource CText}"/>
|
||||
<SolidColorBrush x:Key="BrSubtext0" Color="{StaticResource CSubtext0}"/>
|
||||
<SolidColorBrush x:Key="BrBlue" Color="{StaticResource CBlue}"/>
|
||||
<SolidColorBrush x:Key="BrGreen" Color="{StaticResource CGreen}"/>
|
||||
<SolidColorBrush x:Key="BrRed" Color="{StaticResource CRed}"/>
|
||||
<SolidColorBrush x:Key="BrPeach" Color="{StaticResource CPeach}"/>
|
||||
<SolidColorBrush x:Key="BrLavender" Color="{StaticResource CLavender}"/>
|
||||
|
||||
<!-- Acrylic-like background (semi-transparent fallback) -->
|
||||
<SolidColorBrush x:Key="AcrylicBackgroundBrush" Color="#0F000000"/>
|
||||
|
||||
<!-- Subtle shadow effect for elevation -->
|
||||
<DropShadowEffect x:Key="SubtleDropShadow" BlurRadius="12" ShadowDepth="2" Color="#50000000"/>
|
||||
|
||||
<!-- NAV BUTTON STYLE (icon-only sidebar) -->
|
||||
<Style x:Key="NavBtn" TargetType="RadioButton">
|
||||
<Setter Property="Width" Value="48"/>
|
||||
<Setter Property="Height" Value="48"/>
|
||||
<Setter Property="Margin" Value="6,4"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrSubtext0}"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="RadioButton">
|
||||
<Grid>
|
||||
<Border x:Name="Bg" CornerRadius="10" Background="{TemplateBinding Background}"/>
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="Bg" Property="Background" Value="#28283A"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter TargetName="Bg" Property="Background" Value="{StaticResource BrBlue}"/>
|
||||
<Setter Property="Foreground" Value="#181825"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- ACCENT BUTTON -->
|
||||
<Style x:Key="AccentBtn" TargetType="Button">
|
||||
<Setter Property="Foreground" Value="#181825"/>
|
||||
<Setter Property="FontFamily" Value="Segoe UI Semibold"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="Padding" Value="18,7"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="Bd" CornerRadius="8"
|
||||
Background="{TemplateBinding Background}"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="Bd" Property="Opacity" Value="0.85"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="Bd" Property="Opacity" Value="0.40"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- FLAT TEXTBOX -->
|
||||
<Style x:Key="FlatTb" TargetType="TextBox">
|
||||
<Setter Property="Background" Value="{StaticResource BrSurface0}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrText}"/>
|
||||
<Setter Property="CaretBrush" Value="{StaticResource BrText}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource BrSurface1}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="10,7"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="FontFamily" Value="Segoe UI"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="TextBox">
|
||||
<Border x:Name="Bd" CornerRadius="6"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ScrollViewer x:Name="PART_ContentHost"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsFocused" Value="True">
|
||||
<Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource BrBlue}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- PASSWORD BOX -->
|
||||
<Style x:Key="FlatPb" TargetType="PasswordBox">
|
||||
<Setter Property="Background" Value="{StaticResource BrSurface0}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrText}"/>
|
||||
<Setter Property="CaretBrush" Value="{StaticResource BrText}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource BrSurface1}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="10,7"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="FontFamily" Value="Segoe UI"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="PasswordBox">
|
||||
<Border x:Name="Bd" CornerRadius="6"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ScrollViewer x:Name="PART_ContentHost"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsFocused" Value="True">
|
||||
<Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource BrBlue}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- PROGRESS BAR -->
|
||||
<Style x:Key="ModernPb" TargetType="ProgressBar">
|
||||
<Setter Property="Height" Value="4"/>
|
||||
<Setter Property="Background" Value="{StaticResource BrSurface0}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrBlue}"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ProgressBar">
|
||||
<Grid>
|
||||
<Border CornerRadius="2" Background="{TemplateBinding Background}"/>
|
||||
<Border x:Name="PART_Indicator" CornerRadius="2"
|
||||
Background="{TemplateBinding Foreground}"
|
||||
HorizontalAlignment="Left"/>
|
||||
<Border x:Name="PART_Track"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- DATAGRID -->
|
||||
<Style x:Key="ModernDg" TargetType="DataGrid">
|
||||
<Setter Property="Background" Value="#282A3A"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrText}"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="RowBackground" Value="#282A3A"/>
|
||||
<Setter Property="AlternatingRowBackground" Value="#2D2F42"/>
|
||||
<Setter Property="GridLinesVisibility" Value="Horizontal"/>
|
||||
<Setter Property="HorizontalGridLinesBrush" Value="#37394E"/>
|
||||
<Setter Property="HeadersVisibility" Value="Column"/>
|
||||
<Setter Property="RowHeaderWidth" Value="0"/>
|
||||
<Setter Property="AutoGenerateColumns" Value="True"/>
|
||||
<Setter Property="IsReadOnly" Value="True"/>
|
||||
<Setter Property="SelectionMode" Value="Single"/>
|
||||
<Setter Property="CanUserAddRows" Value="False"/>
|
||||
<Setter Property="CanUserDeleteRows" Value="False"/>
|
||||
<Setter Property="CanUserResizeRows" Value="False"/>
|
||||
<Setter Property="FontFamily" Value="Segoe UI"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="DataGridColumnHeader">
|
||||
<Setter Property="Background" Value="#23243A"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrBlue}"/>
|
||||
<Setter Property="FontFamily" Value="Segoe UI Semibold"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="Padding" Value="10,8"/>
|
||||
<Setter Property="BorderBrush" Value="#37394E"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,0,1"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="DataGridCell">
|
||||
<Setter Property="Padding" Value="8,6"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="DataGridCell">
|
||||
<Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}">
|
||||
<ContentPresenter VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#3C3F58"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource BrBlue}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="DataGridRow">
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#3C3F58"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- Card style for lists / rows -->
|
||||
<Style x:Key="CardStyle" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="8"/>
|
||||
<Setter Property="Background" Value="#23232A"/>
|
||||
<Setter Property="Padding" Value="12"/>
|
||||
<Setter Property="Margin" Value="6"/>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
BIN
HorseRacingPredictor/nuget.exe
Normal file
BIN
HorseRacingPredictor/nuget.exe
Normal file
Binary file not shown.
Reference in New Issue
Block a user