Почему DataTrigger работает с неверным DataContext?C#

Место общения программистов C#
Ответить
Anonymous
 Почему DataTrigger работает с неверным DataContext?

Сообщение Anonymous »

Мой проект выглядит так:
Изображение

TaskClass.cs:

Код: Выделить всё

namespace Library.TaskClassDirectory;

public sealed class TaskClass : INotifyPropertyChanged
{
public TaskClass(
TimeSpan plannedLaborCost,
TimeSpan actualLaborCost)
{
Labor = new Labor(plannedLaborCost, actualLaborCost, this);
}

private Labor _labor = null!;
public Labor Labor
{
get => _labor;
set
{
if (Equals(value, _labor))
{
return;
}

_labor = value;
OnPropertyChanged();
}
}
private TimeSpan _theDifferenceBetweenThePlannedAndActualEndOfTask;
public TimeSpan TheDifferenceBetweenThePlannedAndActualEndOfTask
{
get => _theDifferenceBetweenThePlannedAndActualEndOfTask;
set
{
if (value.Equals(_theDifferenceBetweenThePlannedAndActualEndOfTask))
{
return;
}

_theDifferenceBetweenThePlannedAndActualEndOfTask = value;
OnPropertyChanged();
}
}

internal void TheDifferenceBetween()
{
TheDifferenceBetweenThePlannedAndActualEndOfTask = Labor.PlannedCost.Subtract(
Labor.ActualCost
);

OnPropertyChanged(nameof(TheDifferenceBetweenThePlannedAndActualEndOfTask));
}

public event PropertyChangedEventHandler? PropertyChanged;

public void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

private bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null)
{
if (EqualityComparer.Default.Equals(field, value))
{
return false;
}

field = value;
OnPropertyChanged(propertyName);
return true;
}
}
Labor.cs:

Код: Выделить всё

namespace Library.TaskClassDirectory;

public class Labor: INotifyPropertyChanged
{
public Labor(TimeSpan plannedCost, TimeSpan actualCost, TaskClass taskClass)
{
PlannedCost = plannedCost;
ActualCost = actualCost;
TaskClass = taskClass;
}

private TimeSpan _plannedCost;
public TimeSpan PlannedCost
{
get => _plannedCost;
set
{
if (value.Equals(_plannedCost))
{
return;
}

if (SetField(ref _plannedCost, value))
{
TaskClass?.TheDifferenceBetween();
}
_plannedCost = value;
OnPropertyChanged();
}
}

private TimeSpan _actualCost;
public TimeSpan ActualCost
{
get => _actualCost;
set
{
if (value.Equals(_actualCost))
{
return;
}

if (SetField(ref _actualCost, value))
{
TaskClass?.TheDifferenceBetween();
}

_actualCost = value;
OnPropertyChanged();
}
}

private TaskClass? _taskClass;
public TaskClass? TaskClass
{
get =>  _taskClass;
set
{
if (Equals(value, _taskClass))
{
return;
}

_taskClass = value;
OnPropertyChanged();
}
}

public event PropertyChangedEventHandler? PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null)
{
if (EqualityComparer.Default.Equals(field, value))
return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
}
MainViewModel.cs:

Код: Выделить всё

namespace WpfAppForExample.ViewModels;

public class MainViewModel:INotifyPropertyChanged
{
public ObservableCollection TaskClassList { get; set; }

public MainViewModel()
{
TaskClassList = new ObservableCollection();
GetTaskClassList();

}

private void GetTaskClassList()
{
TaskClass taskClass = new TaskClass(TimeSpan.Zero, TimeSpan.Zero);

TaskClassList.Clear();
TaskClassList.Add(taskClass);
}

public event PropertyChangedEventHandler? PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null)
{
if (EqualityComparer.Default.Equals(field, value))
{
return false;
}

field = value;
OnPropertyChanged(propertyName);
return true;
}
}
OutputValueConverter.cs:

Код: Выделить всё

namespace WpfAppForExample.ViewModels;

public class OutputValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is TimeSpan val && parameter != null && parameter.ToString()!.Contains("IsColor"))
{
if (val > TimeSpan.Zero)
{
return "Red";
}
else if (val < TimeSpan.Zero)
{
return "Green";
}
else
{
return "Black";
}
}

return value;
}

public object ConvertBack(object value, Type targetType, object? parameter, CultureInfo culture) =>
value;
}

MainWindow.xaml.cs:

Код: Выделить всё

namespace WpfAppForExample
{
/// 
/// Interaction logic for MainWindow.xaml
/// 
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
MainWindow.xaml: В строках MainWindow.xaml Среда IDE сообщает, что DataContext указан неправильно, и пишет:
Невозможно разрешить свойство TheDifferenceBetweenThePlannedAndActualEndOfTask в контексте данных типа WpfAppForExample.ViewModels.MainViewModel. >
Однако всё работает корректно. Почему?
Я пробовал следующие настройки привязки DataTrigger, но все они не работают:
  • Binding RelativeSource={RelativeSource Self
  • Binding TaskClassList[this].TheDifferenceBetweenThePlannedAndActualEndOfTask
  • xmlns:taskClassDirectory="clr-namespace:Library.TaskClassDirectory; Assembly=Library"
    Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TaskClassDirectory:TaskClass}}


Подробнее здесь: https://stackoverflow.com/questions/791 ... atacontext
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»