Не работает binding в Dependency Property , UserControl
System.Windows.Data Error: 40 : BindingExpression path error: 'Length' property not found on 'object' ''ClockViewModel' (HashCode=13256970)'. BindingExpression:Path=Length; DataItem='ClockViewModel' (HashCode=13256970); target element is 'ClockUserControl' (Name=''); target property is 'Length' (type 'Double')
Binding не работает. Типа если вписать просто число без Binding , то все сработает. Я не знаю как это пофиксить.
Пожалуйста помогите решить проблему.
И ещо дайте рекомендации, как лучше б сделать , если это должно соответстывать патерну MVVM
MainWindow.xaml
OK
<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"
>
<Window.DataContext>
<vm:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<StackPanel Margin="0 20 0 0">
**<Clocker:ClockUserControl Length="90"/>**
</StackPanel>
</Grid>
</Window>
ERROR
<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"
>
<Window.DataContext>
<vm:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<StackPanel Margin="0 20 0 0">
**<Clocker:ClockUserControl Length="{Binding Path=Length}"/>**
</StackPanel>
</Grid>
</Window>
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()
{
}
public double length = 50;
public double Length
{
get => length;
set { length = value; OnProperyChanged(nameof(length));}
}
}
}
ClockUserControl.xaml.cs
<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>
ClockUserControl.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()
{
this.DataContext = new ClockViewModel();
InitializeComponent();
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 System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ClockUnit.ViewModel
{
public class ClockViewModel : ViewModelBase
{
}
}
Я чуть переписал код, посмотрите его и пожалуйста дайте коментарии как его улучшить, изменение в MainWindow.xaml:
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));
}
}
}
}
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
{
}
}
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>
ClockUserControl.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>
ClockUserControl.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;
}
}
}
}