WPF / XAML / MVVM-UserControl-可重用的DataGrid

时间:2018-11-13 02:12:56

标签: c# wpf mvvm datagrid user-controls

好吧,所以我已经退缩了一步,可能是在错误地称呼我正在尝试做的事情……也就是说,这就是要点:

我的目标:我正在尝试创建一个简单的可重用的DataGrid,可以在基于MVVM的时间卡系统的多个区域中实现。这将用于输入数据以及可视化已提交和批准的考勤卡。请注意,控件本身不是MVVM,因为它的目标是成为可重用的控件,所以View / ViewModel是紧密耦合的。

我的问题:

  1. 绑定没有引发错误,但是它们也不起作用。我可以看到行,输入新行,但是没有数据提交给实现模型的ViewModel。
  2. 我认为我对控件的整个绑定感到困惑。 DataContext在那里,但是说实话,我对它为什么起作用(以及为什么我不得不跳过篮球才能使它起作用)感到非常困惑。我了解可视树和DataGridXXXColumn实现之间的分离。但是我不明白为什么我要在其中实现此控件的VM拒绝接受它(这就是为什么我认为问题1的存在)。
  3. 我已经浏览了数百篇文章,试图使它生效。我以为我了解MVVM / WPF,但是这种绑定似乎比我要好。下面的日期绑定不是故意的。我正在尝试一次解决这一问题,组合框听起来像是个不错的起点(糟糕)。
  4. 如果我错过了任何事情,或者您需要更多信息,请随时询问。

我的视图(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}" />

我的实现中的错误(两个绑定都得到了此错误):

  

不能在类型为'timecard_UserControls _...'的'TimeCardWeekly'属性上设置'Binding'。只能在DependencyObject的DependencyProperty上设置绑定。

我如何不绑定到依赖属性?可以肯定,它们定义正确。

非常感谢您提供的任何/所有帮助。我已经为此花了太长时间了;我必须错过一些基本问题。

编辑: BaseModel使用CallerMemberName(仅是fyi)实现INotifyPropertyChanged

0 个答案:

没有答案