Хорошо, поэтому я загнал себя в угол и, вероятно, неправильно назвал то, что я пытаюсь сделать ... Тем не менее, вот суть:
Моя цель: я пытаюсь создать простой многоразовый DataGrid, который я могу реализовать в нескольких областях системы Time Card на основе MVVM. Это будет использоваться для ввода данных, а также для визуализации уже отправленных и утвержденных временных карт. Обратите внимание, что сам по себе элемент управления не является MVVM, так как его цель - использовать повторно используемый элемент управления, поэтому View / ViewModel тесно связан.
Мои проблемы:
- Привязки не выдают ошибок, но они также не работают. Я могу видеть строки, вводить новые строки, но никакие данные не передаются в мою модель представления, которая реализует мою модель.
- Думаю, я запутался во всей привязке этого элемента управления. DataContext есть, но, честно говоря, я совершенно не понимаю, почему он работает (и почему мне пришлось прыгать через обручи, чтобы заставить его работать). Я понимаю диссоциацию между Visual Tree и реализациями DataGridXXXColumn; но я не понимаю, почему виртуальная машина, в которой я реализую этот элемент управления, отказывается с ним согласиться (поэтому я считаю, что проблема № 1 существует).
- Я просмотрел сотни сообщений, пытаясь заставить это работать. Я думал, что понимаю MVVM / WPF, но тогда этот тип привязки кажется лучше, чем я. Привязки дня, указанные ниже, не подключены специально; Я пытаюсь заняться этим по одному шагу за раз, и поля со списком звучали как хорошее место для начала (упс).
- Если я что-то пропустил или вам нужна дополнительная информация, пожалуйста, не стесняйтесь спрашивать.
My View (UserControl)
<UserControl x:Class="TimeCard.UserControls.WeeklyGridView"
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:TimeCard.UserControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" DataContext="{Binding}">
<UserControl.Resources>
<ResourceDictionary>
<CollectionViewSource x:Key="DgvItemSource" Source="{Binding TimeCardWeekly}"/>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Common;component/Themes/Styling.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.Resources>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="3" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="3" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3"/>
</Grid.ColumnDefinitions>
<DataGrid Grid.Column="1" Grid.Row="1"
AutoGenerateColumns="False" CanUserAddRows="True" CanUserDeleteRows="True"
HeadersVisibility="All" AlternatingRowBackground="WhiteSmoke"
GridLinesVisibility="Horizontal"
CanUserResizeColumns="False" CanUserResizeRows="False" CanUserReorderColumns="False"
ItemsSource="{Binding Source={StaticResource DgvItemSource}, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedTimeCard, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, TargetNullValue={x:Static CollectionView.NewItemPlaceholder}}">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Program" Width="Auto">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=SelectedTimeCard.ProgramNumbers, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
</DataGridComboBoxColumn>
<DataGridTextColumn Header="Mon" Width="Auto" ElementStyle="{StaticResource CenterFieldText}" />
<DataGridTextColumn Header="Tue" Width="Auto" ElementStyle="{StaticResource CenterFieldText}" />
<DataGridTextColumn Header="Wed" Width="Auto" ElementStyle="{StaticResource CenterFieldText}" />
<DataGridTextColumn Header="Thu" Width="Auto" ElementStyle="{StaticResource CenterFieldText}" />
<DataGridTextColumn Header="Fri" Width="Auto" ElementStyle="{StaticResource CenterFieldText}" />
<DataGridTextColumn Header="Sat" Width="Auto" ElementStyle="{StaticResource CenterFieldText}" />
<DataGridTextColumn Header="Sun" Width="Auto" ElementStyle="{StaticResource CenterFieldText}" />
<DataGridComboBoxColumn Header="Category" Width="Auto">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=SelectedTimeCard.CategoryData, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
</DataGridComboBoxColumn>
<DataGridComboBoxColumn Header="Sub Category" Width="Auto">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=SelectedTimeCard.SubcategoryData, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
</DataGridComboBoxColumn>
<DataGridTextColumn Header="Explanation" Width="*">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=SelectedTimeCard.Explanation, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
Моя ViewModel (определена в коде на представлении, поскольку это UserControl):
public partial class WeeklyGridView : UserControl
{
public WeeklyGridView()
{
InitializeComponent();
}
public ObservableCollection<WeeklyGridModel> TimeCardWeekly
{
get => (ObservableCollection<WeeklyGridModel>) GetValue(TimeCardWeeklyDp);
set => SetValue(TimeCardWeeklyDp, value);
}
public static readonly DependencyProperty TimeCardWeeklyDp =
DependencyProperty.Register("TimeCardWeekly", typeof(ObservableCollection<WeeklyGridModel>),
typeof(WeeklyGridView));
public WeeklyGridModel SelectedTimeCard
{
get => (WeeklyGridModel) GetValue(SelectedTimeCardDp);
set => SetValue(SelectedTimeCardDp, value);
}
public static readonly DependencyProperty SelectedTimeCardDp =
DependencyProperty.Register("SelectedTimeCard", typeof(WeeklyGridModel),
typeof(WeeklyGridView));
}
Моя модель:
public class WeeklyGridModel : BaseModel
{
public WeeklyGridModel()
{
}
private List<string> _programNumbers;
public List<string> ProgramNumbers
{
get => Helpers.DummyData.ProgramData;
set { _programNumbers = value; NotifyPropertyChanged(); }
}
private List<string> _categoryData;
public List<string> CategoryData
{
get => Helpers.DummyData.CategoryData;
set { _categoryData = value; NotifyPropertyChanged(); }
}
private List<string> _subcategoryData;
public List<string> SubcategoryData
{
get => Helpers.DummyData.SubcategoryData;
set { _subcategoryData = value; NotifyPropertyChanged(); }
}
private double _monday;
public double Monday
{
get => _monday;
set { _monday = value; NotifyPropertyChanged(); }
}
private double _tuesday;
public double Tuesday
{
get => _tuesday;
set { _tuesday = value; NotifyPropertyChanged(); }
}
private double _wednesday;
public double Wednesday
{
get => _wednesday;
set { _wednesday = value; NotifyPropertyChanged(); }
}
private double _thursday;
public double Thursday
{
get => _thursday;
set { _thursday = value; NotifyPropertyChanged(); }
}
private double _friday;
public double Friday
{
get => _friday;
set { _friday = value; NotifyPropertyChanged(); }
}
private double _saturday;
public double Saturday
{
get => _saturday;
set { _saturday = value; NotifyPropertyChanged(); }
}
private double _sunday;
public double Sunday
{
get => _sunday;
set { _sunday = value; NotifyPropertyChanged(); }
}
private string _explanation;
public string Explanation
{
get => _explanation;
set { _explanation = value; NotifyPropertyChanged(); }
}
}
Ожидаемая реализация:
<userControlsInternal:WeeklyGridView
TimeCardWeekly="{Binding TimeCardWeekly, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedTimeCard="{Binding SelectedTimeCard, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Ошибка в моей реализации (я получаю это для обеих попыток привязки):
Невозможно установить привязку в свойстве TimeCardWeekly типа timecard_UserControls _... Привязка может быть установлена только для свойства DependencyProperty объекта DependencyObject.
Как я не привязан к свойству зависимости? Уверен, они определены правильно.
Любая / вся ваша помощь очень ценится. Я слишком долго этим занимался; Мне должно быть не хватает какой-то фундаментальной проблемы.
Редактировать: BaseModel реализует INotifyPropertyChanged с использованием CallerMemberName (просто к вашему сведению)