У меня есть код (логично) , WPF(MVVM) - написал свой UserControll и хочу узнать как можно было б улучшить код. Так как, он написан для MVVM, но вся логика UserControll написана во View. Пожалуйста дайте мне путь для розвития) Знаю что этот код плохой)
MainWindow.xaml
<Window x:Class="ClockUnit.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ClockUnit.View"
xmlns:Clocker="clr-namespace:ClockUnit.View.UserControls"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
xmlns:vm="clr-namespace:ClockUnit.ViewModel"
xmlns:convert ="clr-namespace:ClockUnit.View.UserControls.Convert"
x:Name="MainWindowForm"
>
<Window.DataContext>
<vm:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<StackPanel Margin="0 20 0 0">
<Clocker:ClockUserControl Length="{Binding Path=DataContext.Length, ElementName=MainWindowForm}"/>
<TextBox Text="{Binding Length , UpdateSourceTrigger=PropertyChanged}" Height="30" Margin="0 20" FontSize="22" FontWeight="Bold"/>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Xaml.Behaviors;
using ClockUnit.ViewModel;
namespace ClockUnit.View
{
/// <summary>
/// Логика взаимодействия для MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
this.DataContext = new MainWindowViewModel();
InitializeComponent();
}
}
}
MainWindowViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace ClockUnit.ViewModel
{
public class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
SendMessage = new RelayCommand(Click);
}
public void Click()
{
Console.WriteLine("Click");
}
public ICommand SendMessage { get; set; }
private double length = 30;
public double Length
{
get => length;
set
{
length = value;
OnProperyChanged(nameof(length));
}
}
}
}
ViewModelBase.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace ClockUnit.ViewModel
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnProperyChanged(string variable)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(variable));
}
}
}
RelayCommand.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace ClockUnit.ViewModel
{
public class RelayCommand : ICommand
{
Action _Execute;
public RelayCommand(Action func)
{
_Execute = func;
}
public event EventHandler CanExecuteChanged;
public virtual bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_Execute?.Invoke();
}
protected void OnCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
}
ClockUserControll.xaml
<UserControl x:Class="ClockUnit.View.UserControls.ClockUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ClockUnit.View.UserControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
xmlns:vm ="clr-namespace:ClockUnit.ViewModel"
>
<UserControl.DataContext>
<vm:ClockViewModel/>
</UserControl.DataContext>
<Grid>
<Canvas Width="200" Height="200" x:Name="ClockF" Background="WhiteSmoke" ></Canvas>
</Grid>
</UserControl>
ClockUserControll.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using ClockUnit.ViewModel;
using ClockUnit.View.UserControls;
using System.ComponentModel;
namespace ClockUnit.View.UserControls
{
/// <summary>
/// Логика взаимодействия для ClockUserControl.xaml
/// </summary>
public partial class ClockUserControl : UserControl
{
public readonly static DependencyProperty LengthKey = DependencyProperty.Register("Length", typeof(double), typeof(ClockUserControl), new PropertyMetadata(90.0));
public double Length
{
get => (double)GetValue(LengthKey);
set => SetValue(LengthKey, value);
}
public ClockUserControl()
{
InitializeComponent();
this.DataContext = new ClockViewModel();
StartTick();
}
public SolidColorBrush ColorLine { get; set; } = new SolidColorBrush(Colors.Black);
public int dx = 100;
public int time;
public void InitClock()
{
Ellipse ellipse = new Ellipse();
ellipse.Width = 200;
ellipse.Height = 200;
ellipse.Stretch = Stretch.Fill;
ellipse.Fill = Brushes.White;
ellipse.Stroke = Brushes.Black;
ellipse.StrokeThickness = 2;
Ellipse point = new Ellipse();
point.Width = 10;
point.Height = 10;
point.Fill = Brushes.Black;
point.Margin = new Thickness(95, 95, 95, 95);
ClockF.Children.Add(ellipse);
ClockF.Children.Add(point);
ClockF.MouseDown += ReturnColor;
}
public async void SecondLine()
{
double second = DateTime.Now.Second;
double angle = (second / 59) * 6.28;
Line line = new Line();
line.X1 = dx;
line.Y1 = dx;
line.X2 = dx + Length * Math.Sin(angle);
line.Y2 = dx - Length * Math.Cos(angle);
line.Stroke = ColorLine;
line.StrokeThickness = 3;
line.MouseDown += MouseD;
ClockF.Children.Add(line);
}
public async void Tick(object sender, EventArgs e)
{
this.Dispatcher.Invoke(() =>
{
ClockF.Children.Clear();
InitClock();
SecondLine();
}
);
}
public void StartTick()
{
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(100);
timer.Tick += Tick;
timer.Start();
}
private void MouseD(object sender , MouseButtonEventArgs e)
{
ColorLine = Brushes.Red;
time = e.Timestamp;
}
private void ReturnColor(object sender, MouseButtonEventArgs e)
{
if(e.Timestamp != time && ColorLine != Brushes.Black)
{
ColorLine = Brushes.Black;
}
}
}
}
ClockViewModel.cs
using ClockUnit.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ClockUnit.ViewModel
{
public class ClockViewModel: ViewModelBase
{
}
}
ТРИГГЕР
<RadioButton
Width="1"
Height="48"
Background="Black"
Command="{Binding ArrowClickCommand, ElementName=uc}"
CommandParameter="Second"
GroupName="arrow"
RenderTransformOrigin="0.5,1"
Cursor="Hand"
Style = "{StaticResource Button.Toggle}"
>
<RadioButton.RenderTransform>
<TransformGroup>
<RotateTransform Angle="{Binding SecondAngle, ElementName=uc}" />
<TranslateTransform X="0" Y="-24" />
</TransformGroup>
</RadioButton.RenderTransform>
<RadioButton.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard TargetProperty="(RenderTransform).(RotateTransform.Angle)">
<DoubleAnimation
To="{Binding SecondAngle, ElementName=uc}"
Duration="0:0:1"
AutoReverse="False"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</RadioButton.Triggers>
</RadioButton>


