CoinViewModel.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. using NTMiner.Core;
  2. using NTMiner.Gpus;
  3. using NTMiner.MinerStudio;
  4. using NTMiner.MinerStudio.Vms;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text.RegularExpressions;
  10. using System.Threading.Tasks;
  11. using System.Windows.Forms;
  12. using System.Windows.Input;
  13. namespace NTMiner.Vms {
  14. public class CoinViewModel : ViewModelBase, ICoin, IEditableViewModel {
  15. public static readonly CoinViewModel Empty = new CoinViewModel(Guid.Empty) {
  16. _algoId = Guid.Empty,
  17. _code = string.Empty,
  18. _enName = string.Empty,
  19. _cnName = string.Empty,
  20. _icon = string.Empty,
  21. _id = Guid.Empty,
  22. _testWallet = string.Empty,
  23. _justAsDualCoin = false,
  24. _walletRegexPattern = string.Empty,
  25. _notice = string.Empty,
  26. _tutorialUrl = string.Empty,
  27. _iconImageSource = string.Empty,
  28. _minGpuMemoryGb = 0,
  29. _isHot = false,
  30. _kernelBrand = string.Empty
  31. };
  32. public static readonly CoinViewModel PleaseSelect = new CoinViewModel(Guid.Empty) {
  33. _code = "不指定",
  34. _iconImageSource = MinerClientTempPath.GetIconFileFullName("ETH.png")
  35. };
  36. public static readonly CoinViewModel DualCoinEnabled = new CoinViewModel(Guid.Empty) {
  37. _code = "启用了双挖"
  38. };
  39. private Guid _id;
  40. private string _code;
  41. private Guid _algoId;
  42. private string _testWallet;
  43. private string _enName;
  44. private string _cnName;
  45. private string _icon;
  46. private string _walletRegexPattern;
  47. private bool _justAsDualCoin;
  48. private string _notice;
  49. private string _iconImageSource;
  50. private string _tutorialUrl;
  51. private bool _isHot;
  52. private string _kernelBrand;
  53. private double _minGpuMemoryGb;
  54. private List<GpuProfileViewModel> _gpuProfileVms;
  55. private readonly CoinIncomeViewModel _coinIncomeVm;
  56. public CoinIncomeViewModel CoinIncomeVm {
  57. get {
  58. return _coinIncomeVm;
  59. }
  60. }
  61. public Guid GetId() {
  62. return this.Id;
  63. }
  64. public ICommand Remove { get; private set; }
  65. public ICommand Edit { get; private set; }
  66. public ICommand AddPool { get; private set; }
  67. public ICommand AddWallet { get; private set; }
  68. public ICommand Save { get; private set; }
  69. public ICommand BrowseIcon { get; private set; }
  70. public ICommand AddOverClockData { get; private set; }
  71. public ICommand AddNTMinerWallet { get; private set; }
  72. public ICommand ApplyTemplateOverClock { get; private set; }
  73. public ICommand ApplyCustomOverClock { get; private set; }
  74. public ICommand RestoreOverClock { get; private set; }
  75. public ICommand FillOverClockForms { get; private set; }
  76. public ICommand FillOverClockForm { get; private set; }
  77. [Obsolete(message: NTKeyword.WpfDesignOnly, error: true)]
  78. public CoinViewModel() {
  79. if (!WpfUtil.IsInDesignMode) {
  80. throw new InvalidProgramException(NTKeyword.WpfDesignOnly);
  81. }
  82. }
  83. public CoinViewModel(ICoin data) : this(data.GetId()) {
  84. _code = data.Code;
  85. _algoId = data.AlgoId;
  86. _testWallet = data.TestWallet;
  87. _enName = data.EnName;
  88. _cnName = data.CnName;
  89. _icon = data.Icon;
  90. _walletRegexPattern = data.WalletRegexPattern;
  91. _justAsDualCoin = data.JustAsDualCoin;
  92. _notice = data.Notice;
  93. _tutorialUrl = data.TutorialUrl;
  94. _isHot = data.IsHot;
  95. _kernelBrand = data.KernelBrand;
  96. _minGpuMemoryGb = data.MinGpuMemoryGb;
  97. string iconFileFullName = MinerClientTempPath.GetIconFileFullName(data.Icon);
  98. if (!string.IsNullOrEmpty(iconFileFullName) && File.Exists(iconFileFullName)) {
  99. _iconImageSource = iconFileFullName;
  100. }
  101. }
  102. public CoinViewModel(CoinViewModel vm) : this((ICoin)vm) {
  103. _iconImageSource = vm.IconImageSource;
  104. }
  105. private void ApplyOverClock() {
  106. VirtualRoot.Execute(new CoinOverClockCommand(this.Id));
  107. }
  108. private void FillOverClock(OverClockDataViewModel data) {
  109. if (IsOverClockGpuAll) {
  110. GpuAllProfileVm.Update(data);
  111. VirtualRoot.Execute(new AddOrUpdateGpuProfileCommand(GpuAllProfileVm));
  112. }
  113. else {
  114. foreach (var item in GpuProfileVms) {
  115. if (item.Index == NTMinerContext.GpuAllId) {
  116. continue;
  117. }
  118. item.Update(data);
  119. VirtualRoot.Execute(new AddOrUpdateGpuProfileCommand(item));
  120. }
  121. }
  122. }
  123. public CoinViewModel(Guid id) {
  124. _id = id;
  125. _coinIncomeVm = new CoinIncomeViewModel(this);
  126. this.BrowseIcon = new DelegateCommand(() => {
  127. if (!DevMode.IsDevMode) {
  128. return;
  129. }
  130. OpenFileDialog openFileDialog = new OpenFileDialog {
  131. InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
  132. Filter = "png (*.png)|*.png",
  133. FilterIndex = 1
  134. };
  135. if (openFileDialog.ShowDialog() == DialogResult.OK) {
  136. try {
  137. string iconFileFullName = openFileDialog.FileName;
  138. this.IconImageSource = new Uri(iconFileFullName, UriKind.Absolute).ToString();
  139. string pngFileName = Path.GetFileName(iconFileFullName);
  140. if (AppRoot.CoinVms.AllCoins.Any(a => a.Icon == pngFileName && a.Id != this.Id)) {
  141. throw new ValidationException("币种图标不能重名");
  142. }
  143. this.Icon = pngFileName;
  144. }
  145. catch (Exception e) {
  146. Logger.ErrorDebugLine(e);
  147. }
  148. }
  149. });
  150. this.ApplyTemplateOverClock = new DelegateCommand<OverClockDataViewModel>((data) => {
  151. this.ShowSoftDialog(new DialogWindowViewModel(message: data.Tooltip, title: "确定应用该超频设置吗?", onYes: () => {
  152. FillOverClock(data);
  153. ApplyOverClock();
  154. }));
  155. });
  156. this.ApplyCustomOverClock = new DelegateCommand(() => {
  157. this.ShowSoftDialog(new DialogWindowViewModel(message: $"确定应用您的自定义超频吗?", title: "确认自定义超频", onYes: () => {
  158. ApplyOverClock();
  159. }));
  160. });
  161. this.RestoreOverClock = new DelegateCommand(() => {
  162. this.ShowSoftDialog(new DialogWindowViewModel(message: $"确定恢复默认吗?", title: "确认", onYes: () => {
  163. NTMinerContext.Instance.GpuSet.OverClock.Restore();
  164. this.IsOverClockEnabled = false;
  165. }));
  166. });
  167. this.FillOverClockForm = new DelegateCommand<OverClockDataViewModel>((data) => {
  168. FillOverClock(data);
  169. });
  170. this.FillOverClockForms = new DelegateCommand(() => {
  171. this.ShowSoftDialog(new DialogWindowViewModel(message: "确定将统一超频的数据一键填充到每张卡吗?", title: "一键填充表单", onYes: () => {
  172. var data = GpuAllProfileVm;
  173. foreach (var item in GpuProfileVms) {
  174. if (item.Index == NTMinerContext.GpuAllId) {
  175. continue;
  176. }
  177. item.Update((IOverClockInput)data);
  178. VirtualRoot.Execute(new AddOrUpdateGpuProfileCommand(item));
  179. }
  180. }));
  181. });
  182. this.AddOverClockData = new DelegateCommand(() => {
  183. new OverClockDataViewModel(Guid.NewGuid()) {
  184. CoinId = this.Id
  185. }.Edit.Execute(FormType.Add);
  186. });
  187. this.AddNTMinerWallet = new DelegateCommand(() => {
  188. new NTMinerWalletViewModel(Guid.NewGuid()) {
  189. CoinCode = this.Code
  190. }.Edit.Execute(FormType.Add);
  191. });
  192. this.Save = new DelegateCommand(() => {
  193. if (this.Id == Guid.Empty) {
  194. return;
  195. }
  196. if (NTMinerContext.Instance.ServerContext.CoinSet.Contains(this.Id)) {
  197. VirtualRoot.Execute(new UpdateCoinCommand(this));
  198. }
  199. else {
  200. VirtualRoot.Execute(new AddCoinCommand(this));
  201. }
  202. VirtualRoot.Execute(new CloseWindowCommand(this.Id));
  203. });
  204. this.Edit = new DelegateCommand<FormType?>((formType) => {
  205. if (this.Id == Guid.Empty) {
  206. return;
  207. }
  208. VirtualRoot.Execute(new EditCoinCommand(formType ?? FormType.Edit, this));
  209. });
  210. this.Remove = new DelegateCommand(() => {
  211. if (this.Id == Guid.Empty) {
  212. return;
  213. }
  214. this.ShowSoftDialog(new DialogWindowViewModel(message: $"您确定删除{this.Code}币种吗?", title: "确认", onYes: () => {
  215. VirtualRoot.Execute(new RemoveCoinCommand(this.Id));
  216. }));
  217. });
  218. this.AddPool = new DelegateCommand(() => {
  219. int sortNumber = this.Pools.Count == 0 ? 1 : this.Pools.Max(a => a.SortNumber) + 1;
  220. new PoolViewModel(Guid.NewGuid()) {
  221. CoinId = Id,
  222. SortNumber = sortNumber
  223. }.Edit.Execute(FormType.Add);
  224. });
  225. this.AddWallet = new DelegateCommand(() => {
  226. int sortNumber = this.Wallets.Count == 0 ? 1 : this.Wallets.Max(a => a.SortNumber) + 1;
  227. new WalletViewModel(Guid.NewGuid()) {
  228. CoinId = Id,
  229. SortNumber = sortNumber
  230. }.Edit.Execute(FormType.Add);
  231. });
  232. }
  233. public void OnOverClockPropertiesChanges() {
  234. OnPropertyChanged(nameof(IsOverClockEnabled));
  235. OnPropertyChanged(nameof(IsOverClockGpuAll));
  236. _gpuAllProfileVm = null;
  237. _gpuProfileVms = null;
  238. OnPropertyChanged(nameof(GpuAllProfileVm));
  239. OnPropertyChanged(nameof(GpuProfileVms));
  240. }
  241. public bool IsOverClockEnabled {
  242. get { return NTMinerContext.Instance.GpuProfileSet.IsOverClockEnabled(this.Id); }
  243. set {
  244. NTMinerContext.Instance.GpuProfileSet.SetIsOverClockEnabled(this.Id, value);
  245. OnPropertyChanged(nameof(IsOverClockEnabled));
  246. }
  247. }
  248. public bool IsOverClockGpuAll {
  249. get { return NTMinerContext.Instance.GpuProfileSet.IsOverClockGpuAll(this.Id); }
  250. set {
  251. NTMinerContext.Instance.GpuProfileSet.SetIsOverClockGpuAll(this.Id, value);
  252. OnPropertyChanged(nameof(IsOverClockGpuAll));
  253. }
  254. }
  255. private GpuProfileViewModel _gpuAllProfileVm;
  256. public GpuProfileViewModel GpuAllProfileVm {
  257. get {
  258. if (_gpuAllProfileVm == null) {
  259. _gpuAllProfileVm = AppRoot.GpuProfileVms.GpuAllVm(this.Id);
  260. }
  261. return _gpuAllProfileVm;
  262. }
  263. set {
  264. _gpuAllProfileVm = value;
  265. OnPropertyChanged(nameof(GpuAllProfileVm));
  266. }
  267. }
  268. public List<GpuProfileViewModel> GpuProfileVms {
  269. get {
  270. if (_gpuProfileVms == null) {
  271. _gpuProfileVms = AppRoot.GpuProfileVms.List(this.Id);
  272. }
  273. return _gpuProfileVms;
  274. }
  275. set {
  276. _gpuProfileVms = value;
  277. OnPropertyChanged(nameof(GpuProfileVms));
  278. }
  279. }
  280. public ShareViewModel ShareVm {
  281. get {
  282. return AppRoot.ShareVms.GetOrCreate(this.Id);
  283. }
  284. }
  285. public Guid Id {
  286. get => _id;
  287. private set {
  288. if (_id != value) {
  289. _id = value;
  290. OnPropertyChanged(nameof(Id));
  291. }
  292. }
  293. }
  294. public bool IsSupported {
  295. get {
  296. if (this.Id == PleaseSelect.Id || NTMinerContext.Instance.GpuSet.GpuType.IsEmpty()) {
  297. return true;
  298. }
  299. foreach (var coinKernel in NTMinerContext.Instance.ServerContext.CoinKernelSet.AsEnumerable().Where(a => a.CoinId == this.Id).ToArray()) {
  300. if (coinKernel.SupportedGpu.IsSupportedGpu(NTMinerContext.Instance.GpuSet.GpuType)) {
  301. return true;
  302. }
  303. }
  304. return false;
  305. }
  306. }
  307. public string Code {
  308. get => _code;
  309. set {
  310. if (_code != value) {
  311. _code = value;
  312. OnPropertyChanged(nameof(Code));
  313. if (this.Id == Empty.Id || this.Id == PleaseSelect.Id || this.Id == DualCoinEnabled.Id) {
  314. return;
  315. }
  316. if (string.IsNullOrEmpty(value)) {
  317. throw new ValidationException("编码是必须的");
  318. }
  319. if (AppRoot.CoinVms.TryGetCoinVm(value, out CoinViewModel coinVm) && coinVm.Id != this.Id) {
  320. throw new ValidationException("重复的币种编码");
  321. }
  322. }
  323. }
  324. }
  325. public string EnName {
  326. get => _enName;
  327. set {
  328. if (_enName != value) {
  329. _enName = value;
  330. OnPropertyChanged(nameof(EnName));
  331. OnPropertyChanged(nameof(FullName));
  332. }
  333. }
  334. }
  335. public string CnName {
  336. get => _cnName;
  337. set {
  338. if (_cnName != value) {
  339. _cnName = value;
  340. OnPropertyChanged(nameof(CnName));
  341. OnPropertyChanged(nameof(FullName));
  342. }
  343. }
  344. }
  345. public string FullName {
  346. get {
  347. return $"{EnName}-{CnName}";
  348. }
  349. }
  350. public string Icon {
  351. get { return _icon; }
  352. set {
  353. if (_icon != value) {
  354. _icon = value;
  355. OnPropertyChanged(nameof(Icon));
  356. RefreshIcon();
  357. }
  358. }
  359. }
  360. public void RefreshIcon() {
  361. string iconFileFullName = MinerClientTempPath.GetIconFileFullName(this.Icon);
  362. // 如果磁盘上存在则不再下载,所以如果要更新币种图标则需重命名Icon文件
  363. if (string.IsNullOrEmpty(iconFileFullName)) {
  364. return;
  365. }
  366. if (File.Exists(iconFileFullName)) {
  367. return;
  368. }
  369. using (var webClient = VirtualRoot.CreateWebClient(10)) {
  370. webClient.DownloadFileCompleted += (object sender, System.ComponentModel.AsyncCompletedEventArgs e) => {
  371. if (!e.Cancelled && e.Error == null) {
  372. VirtualRoot.RaiseEvent(new CoinIconDownloadedEvent(Guid.Empty, this));
  373. }
  374. else {
  375. File.Delete(iconFileFullName);
  376. }
  377. };
  378. webClient.DownloadFileAsync(new Uri($"https://minerjson.{NTKeyword.CloudFileDomain}/coin_icons/{this.Icon}"), iconFileFullName);
  379. }
  380. }
  381. public string IconImageSource {
  382. get => _iconImageSource;
  383. set {
  384. _iconImageSource = value;
  385. OnPropertyChanged(nameof(IconImageSource));
  386. }
  387. }
  388. public Guid AlgoId {
  389. get => _algoId;
  390. set {
  391. if (_algoId != value) {
  392. _algoId = value;
  393. OnPropertyChanged(nameof(AlgoId));
  394. OnPropertyChanged(nameof(AlgoItem));
  395. }
  396. }
  397. }
  398. public string Algo {
  399. get {
  400. return AlgoItem.Value;
  401. }
  402. }
  403. public SysDicItemViewModel AlgoItem {
  404. get {
  405. if (this.AlgoId == Guid.Empty) {
  406. return SysDicItemViewModel.PleaseSelect;
  407. }
  408. if (AppRoot.SysDicItemVms.TryGetValue(this.AlgoId, out SysDicItemViewModel item)) {
  409. return item;
  410. }
  411. return SysDicItemViewModel.PleaseSelect;
  412. }
  413. set {
  414. if (value == null) {
  415. value = SysDicItemViewModel.PleaseSelect;
  416. }
  417. this.AlgoId = value.Id;
  418. }
  419. }
  420. public AppRoot.SysDicItemViewModels SysDicItemVms {
  421. get {
  422. return AppRoot.SysDicItemVms;
  423. }
  424. }
  425. public string TestWallet {
  426. get => _testWallet;
  427. set {
  428. if (_testWallet != value) {
  429. _testWallet = value ?? string.Empty;
  430. OnPropertyChanged(nameof(TestWallet));
  431. if (!string.IsNullOrEmpty(WalletRegexPattern)) {
  432. Regex regex = VirtualRoot.GetRegex(WalletRegexPattern);
  433. if (!regex.IsMatch(value ?? string.Empty)) {
  434. throw new ValidationException("钱包地址格式不正确。");
  435. }
  436. }
  437. }
  438. }
  439. }
  440. public string WalletRegexPattern {
  441. get => _walletRegexPattern;
  442. set {
  443. if (_walletRegexPattern != value) {
  444. _walletRegexPattern = value;
  445. OnPropertyChanged(nameof(WalletRegexPattern));
  446. OnPropertyChanged(nameof(TestWallet));
  447. }
  448. }
  449. }
  450. public bool JustAsDualCoin {
  451. get => _justAsDualCoin;
  452. set {
  453. if (_justAsDualCoin != value) {
  454. _justAsDualCoin = value;
  455. OnPropertyChanged(nameof(JustAsDualCoin));
  456. }
  457. }
  458. }
  459. public string Notice {
  460. get { return _notice; }
  461. set {
  462. if (_notice != value) {
  463. _notice = value;
  464. OnPropertyChanged(nameof(Notice));
  465. }
  466. }
  467. }
  468. public string TutorialUrl {
  469. get => _tutorialUrl;
  470. set {
  471. if (value != _tutorialUrl) {
  472. _tutorialUrl = value;
  473. OnPropertyChanged(nameof(TutorialUrl));
  474. }
  475. }
  476. }
  477. public bool IsHot {
  478. get { return _isHot; }
  479. set {
  480. _isHot = value;
  481. OnPropertyChanged(nameof(IsHot));
  482. }
  483. }
  484. public string KernelBrand {
  485. get { return _kernelBrand; }
  486. set {
  487. if (_kernelBrand != value) {
  488. _kernelBrand = value;
  489. OnPropertyChanged(nameof(KernelBrand));
  490. if (string.IsNullOrEmpty(value)) {
  491. _kernelBrandDic.Clear();
  492. }
  493. }
  494. }
  495. }
  496. public double MinGpuMemoryGb {
  497. get { return _minGpuMemoryGb; }
  498. set {
  499. if (_minGpuMemoryGb != value) {
  500. _minGpuMemoryGb = value;
  501. OnPropertyChanged(nameof(MinGpuMemoryGb));
  502. OnPropertyChanged(nameof(MinGpuMemoryGbText));
  503. }
  504. }
  505. }
  506. public string MinGpuMemoryGbText {
  507. get {
  508. if (MinGpuMemoryGb == 0) {
  509. return "-";
  510. }
  511. return MinGpuMemoryGb.ToString() + " Gb";
  512. }
  513. }
  514. private string _oldKernelBrand;
  515. private readonly Dictionary<GpuType, Guid> _kernelBrandDic = new Dictionary<GpuType, Guid>();
  516. private Dictionary<GpuType, Guid> KernelBrandDic {
  517. get {
  518. if (string.IsNullOrEmpty(this.KernelBrand)) {
  519. return _kernelBrandDic;
  520. }
  521. if (_oldKernelBrand == this.KernelBrand) {
  522. return _kernelBrandDic;
  523. }
  524. _oldKernelBrand = this.KernelBrand;
  525. if (_kernelBrandDic.ContainsKey(GpuType.AMD)) {
  526. _kernelBrandDic[GpuType.AMD] = this.GetKernelBrandId(GpuType.AMD);
  527. }
  528. else {
  529. _kernelBrandDic.Add(GpuType.AMD, this.GetKernelBrandId(GpuType.AMD));
  530. }
  531. if (_kernelBrandDic.ContainsKey(GpuType.NVIDIA)) {
  532. _kernelBrandDic[GpuType.NVIDIA] = this.GetKernelBrandId(GpuType.NVIDIA);
  533. }
  534. else {
  535. _kernelBrandDic.Add(GpuType.NVIDIA, this.GetKernelBrandId(GpuType.NVIDIA));
  536. }
  537. return _kernelBrandDic;
  538. }
  539. }
  540. public SysDicItemViewModel NKernelBrand {
  541. get {
  542. if (KernelBrandDic.TryGetValue(GpuType.NVIDIA, out Guid id)) {
  543. if (AppRoot.SysDicItemViewModels.Instance.TryGetValue(id, out SysDicItemViewModel sysDicItemVm)) {
  544. return sysDicItemVm;
  545. }
  546. return null;
  547. }
  548. return null;
  549. }
  550. set {
  551. if (value != NKernelBrand) {
  552. if (value == SysDicItemViewModel.PleaseSelect) {
  553. value = null;
  554. }
  555. SetKernelBrand(value, AKernelBrand);
  556. OnPropertyChanged(nameof(NKernelBrand));
  557. }
  558. }
  559. }
  560. public SysDicItemViewModel AKernelBrand {
  561. get {
  562. if (KernelBrandDic.TryGetValue(GpuType.AMD, out Guid id)) {
  563. if (AppRoot.SysDicItemViewModels.Instance.TryGetValue(id, out SysDicItemViewModel sysDicItemVm)) {
  564. return sysDicItemVm;
  565. }
  566. return null;
  567. }
  568. return null;
  569. }
  570. set {
  571. if (value != AKernelBrand) {
  572. if (value == SysDicItemViewModel.PleaseSelect) {
  573. value = null;
  574. }
  575. SetKernelBrand(NKernelBrand, value);
  576. OnPropertyChanged(nameof(AKernelBrand));
  577. }
  578. }
  579. }
  580. private void SetKernelBrand(SysDicItemViewModel n, SysDicItemViewModel a) {
  581. if (n == null) {
  582. if (a == null) {
  583. this.KernelBrand = string.Empty;
  584. }
  585. else {
  586. this.KernelBrand = $"{nameof(GpuType.AMD)}:{a.Id.ToString()}";
  587. }
  588. }
  589. else {
  590. if (a == null) {
  591. this.KernelBrand = $"{nameof(GpuType.NVIDIA)}:{n.Id.ToString()}";
  592. }
  593. else {
  594. this.KernelBrand = $"{nameof(GpuType.NVIDIA)}:{n.Id.ToString()};{nameof(GpuType.AMD)}:{a.Id.ToString()}";
  595. }
  596. }
  597. }
  598. public CoinProfileViewModel CoinProfile {
  599. get {
  600. if (!NTMinerContext.Instance.ServerContext.CoinSet.Contains(this.Id)) {
  601. return null;
  602. }
  603. return AppRoot.CoinProfileVms.GetOrCreateCoinProfile(this.Id);
  604. }
  605. }
  606. public List<PoolViewModel> Pools {
  607. get {
  608. return AppRoot.PoolVms.AllPools.Where(a => a.CoinId == this.Id).OrderBy(a => a.SortNumber).ToList();
  609. }
  610. }
  611. private IEnumerable<PoolViewModel> GetOptionPools() {
  612. if (this.Id == PleaseSelect.Id) {
  613. yield return PoolViewModel.PleaseSelect;
  614. }
  615. else {
  616. yield return PoolViewModel.PleaseSelect;
  617. foreach (var item in Pools) {
  618. yield return item;
  619. }
  620. }
  621. }
  622. public List<PoolViewModel> OptionPools {
  623. get {
  624. return GetOptionPools().ToList();
  625. }
  626. }
  627. private static readonly Dictionary<Guid, WalletViewModel> s_testWallets = new Dictionary<Guid, WalletViewModel>();
  628. public WalletViewModel TestWalletVm {
  629. get {
  630. if (string.IsNullOrEmpty(this.TestWallet)) {
  631. return WalletViewModel.CreateEmptyWallet(this.Id);
  632. }
  633. if (!s_testWallets.ContainsKey(this.GetId())) {
  634. s_testWallets.Add(this.GetId(), new WalletViewModel(this.GetId()) {
  635. Address = this.TestWallet,
  636. CoinId = this.GetId(),
  637. Name = this.Code + "测试地址",
  638. SortNumber = 0
  639. });
  640. }
  641. return s_testWallets[this.GetId()];
  642. }
  643. }
  644. public List<OverClockDataViewModel> OverClockDatas {
  645. get {
  646. return MinerStudioRoot.OverClockDataVms.Items.Where(a => a.CoinId == this.Id).ToList();
  647. }
  648. }
  649. public List<NTMinerWalletViewModel> NTMinerWallets {
  650. get {
  651. return MinerStudioRoot.NTMinerWalletVms.Items.Where(a => a.CoinCode == this.Code).ToList();
  652. }
  653. }
  654. private IEnumerable<WalletViewModel> GetWallets() {
  655. // 如果不是开发者模式就不要展示测试钱包了
  656. if (DevMode.IsDevMode) {
  657. if (!string.IsNullOrEmpty(TestWallet)) {
  658. yield return TestWalletVm;
  659. }
  660. }
  661. foreach (var item in AppRoot.WalletVms.WalletList.Where(a => a.CoinId == this.Id).OrderBy(a => a.SortNumber).ToList()) {
  662. yield return item;
  663. }
  664. }
  665. public List<WalletViewModel> Wallets {
  666. get {
  667. if (WpfUtil.IsInDesignMode) {
  668. return new List<WalletViewModel>();
  669. }
  670. return GetWallets().ToList();
  671. }
  672. }
  673. private IEnumerable<WalletViewModel> GetWalletItems() {
  674. yield return WalletViewModel.PleaseSelect;
  675. foreach (var item in Wallets) {
  676. yield return item;
  677. }
  678. }
  679. public List<WalletViewModel> WalletItems {
  680. get {
  681. return GetWalletItems().ToList();
  682. }
  683. }
  684. public List<CoinKernelViewModel> CoinKernels {
  685. get {
  686. return AppRoot.CoinKernelVms.AllCoinKernels
  687. .Where(a => a.CoinId == this.Id && a.Kernel != null && a.Kernel.PublishState == PublishStatus.Published)
  688. .OrderBy(a => a.Kernel.Code)
  689. .ThenByDescending(a => a.Kernel.Version).ToList();
  690. }
  691. }
  692. public CoinKernelViewModel CoinKernel {
  693. get {
  694. var list = CoinKernels;
  695. CoinKernelViewModel coinKernel = null;
  696. if (CoinProfile != null) {
  697. coinKernel = list.FirstOrDefault(a => a.Id == CoinProfile.CoinKernelId);
  698. }
  699. // 选中的记录可能已经不存在
  700. if (coinKernel == null) {
  701. // 首先选择推荐的
  702. coinKernel = list.FirstOrDefault(a => a.IsRecommend);
  703. if (coinKernel == null) {
  704. // 推荐的不存在,选择第一个
  705. coinKernel = list.FirstOrDefault();
  706. }
  707. if (coinKernel != null) {
  708. this.CoinKernel = coinKernel;
  709. }
  710. }
  711. return coinKernel;
  712. }
  713. set {
  714. if (CoinProfile == null) {
  715. return;
  716. }
  717. if (value != null && value.Id != Guid.Empty) {
  718. CoinProfile.CoinKernelId = value.Id;
  719. OnPropertyChanged(nameof(CoinKernel));
  720. // 不必判断该对象是否是主界面上当前展示的对象,因为若不是主界面上当前显式的对象的话没有机会变更
  721. NTMinerContext.RefreshArgsAssembly.Invoke("币种Profile上引用的币种内核发生了切换");
  722. }
  723. }
  724. }
  725. }
  726. }