Не работает 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;
            }
            
        }



    }
}

Ответы (0 шт):