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;
}
}
}
}
<vm:MainWindowViewModel/>- плохо. А проблема ваша в том, что у вашегоUserControlзадан свойDataContext, в котором и ищется свойство, вам даже ошибка пишет "Нет свойства 'Length' в'ClockViewModel". Что делать? Тут зависит от того, что это UserControl должен делать, за что отвечает. Если его задача бы просто контролом (какTextBoxнапример), то у него вообще не должно бытьVMслоя, он должен быть независимым, отдавая наружу только свои DP, а внутри должно быть что-то по типу{Binding Length, ElementName=uc}. – EvgeniyZ Jul 17 '22 at 15:31uc- имя заданное самомуUserControlчерезx:Name="uc". Если задача вашего контрола быть как "страница", то здесь вам надо идти от обратного, делать что-то по типу этого, где вы по типу задаете нужный вид. – EvgeniyZ Jul 17 '22 at 15:33