C# 在WPF MVVM可观察集合中实现IsDirty

C# 在WPF MVVM可观察集合中实现IsDirty,c#,wpf,mvvm,C#,Wpf,Mvvm,我有一个模型: namespace CCBDPlayer.Models { public class Schedule : DependencyObject, IEquatable<Schedule>, INotifyPropertyChanged { private DateTime _scheduledStart; private DateTime _scheduledEnd; private bool _enabled; private stri

我有一个模型:

namespace CCBDPlayer.Models
{
public class Schedule : DependencyObject, IEquatable<Schedule>, INotifyPropertyChanged
{
    private DateTime _scheduledStart;
    private DateTime _scheduledEnd;
    private bool _enabled;
    private string _url;
    private bool _isDirty;

    public event PropertyChangedEventHandler PropertyChanged;

    public Schedule() { }

    public static readonly DependencyProperty IsDirtyProperty = 
        DependencyProperty.Register("IsDirty", typeof(Boolean),typeof(Schedule));
    public DateTime ScheduledStart
    {
        get { return _scheduledStart; }
        set
        {
            _scheduledStart = value;
            OnPropertyChanged(new PropertyChangedEventArgs("ScheduledStart"));
        }
    }
    public DateTime ScheduledEnd
    {
        get { return _scheduledEnd; }
        set
        {
            if (value < ScheduledStart)
            {
                throw new ArgumentException("Scheduled End cannot be earlier than Scheduled Start.");
            }
            else
            {
                _scheduledEnd = value;
                OnPropertyChanged(new PropertyChangedEventArgs("ScheduledEnd"));
            }
        }
    }
    public bool Enabled
    {
        get { return _enabled; }
        set
        {
            _enabled = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Enabled"));
            IsDirty = true;
        }
    }
    public string Url
    {
        get { return _url; }
        set
        {
            _url = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Url"));
            IsDirty = true;
        }
    }

    [XmlIgnoreAttribute]
    public bool IsDirty
    {
        get { return (bool)GetValue(IsDirtyProperty); }
        set { SetValue(IsDirtyProperty, value); }
    }

    public bool Equals(Schedule other)
    {
        if(this.ScheduledStart == other.ScheduledStart && this.ScheduledEnd == other.ScheduledEnd 
            && this.Enabled == other.Enabled && this.Url == other.Url)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, e);
        }
    }
}
名称空间CCBDPlayer.Models
{
公共类明细表:DependencyObject、IEquatable、INotifyPropertyChanged
{
专用日期时间(U scheduledStart);;
专用日期时间(已计划);
启用私有布尔;
私有字符串url;
私人住宅;
公共事件属性更改事件处理程序属性更改;
公共时间表(){}
公共静态只读从属属性IsDirtyProperty=
DependencyProperty.Register(“IsDirty”、typeof(布尔)、typeof(Schedule));
公共日期时间计划开始
{
获取{return}
设置
{
_scheduledStart=值;
OnPropertyChanged(新PropertyChangedEventArgs(“ScheduledStart”);
}
}
计划的公共日期时间
{
获取{return}
设置
{
if(值
}

此模型用于我的ViewModel中存在的ObservableCollection。ObservableCollection绑定到我视图中的ItemsControl:

            <ItemsControl ItemsSource="{Binding Config.Schedules}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border x:Name="ScheduleBorder" BorderBrush="Black" BorderThickness="1" Margin="5,5" VerticalAlignment="Top">
                        <Grid VerticalAlignment="Top">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="4*" />
                                <RowDefinition Height="2*" />
                            </Grid.RowDefinitions>
                            <Grid Grid.Row="0">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="2*" />
                                    <ColumnDefinition Width="3*" />
                                    <ColumnDefinition Width="1*" />
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition />
                                    <RowDefinition />
                                    <RowDefinition />
                                </Grid.RowDefinitions>
                                <Label Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Content="Scheduled Start" VerticalAlignment="Top"/>
                                <xctk:DateTimePicker Grid.Column="1" Grid.Row="0" Value="{Binding ScheduledStart}" Margin="0,2" VerticalAlignment="Center"  />
                                <Label Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" Content="Scheduled End" />
                                <xctk:DateTimePicker Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" Value="{Binding ScheduledEnd}" Margin="0.2" />
                                <Button Grid.Row="0" Grid.Column="2" Margin="5,5" Background="White" VerticalAlignment="Top" Width="15" Height="15" 
                                        Command="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl}, Path=DataContext.RemoveScheduleCommand}" CommandParameter="{Binding}">
                                    <Image Source="Images/delete-button.png"/>
                                </Button>
                                <Label Grid.Column="0" Grid.Row="2" HorizontalAlignment="Left" Content="Url" VerticalAlignment="Top"/>
                                <TextBox Grid.Column="1" Grid.Row="2" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding Url}" Width="Auto"/>
                            </Grid>
                            <Grid Grid.Row="1">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="3*"/>
                                    <ColumnDefinition Width="1*" />
                                </Grid.ColumnDefinitions>
                                <CheckBox Content="Enable" Margin="5" IsChecked="{Binding Enabled}"/>
                                <Button Grid.Column="1" HorizontalAlignment="Right" Width="65" Content="Save" Margin="0, 2"/>
                            </Grid>
                        </Grid>
                    </Border>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding Path=IsDirty}" Value="true">
                            <Setter Property="Background" TargetName="ScheduleBorder" Value="Yellow"/>
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

我只需要在初始化模型实例之后才能设置IsDirty。有什么建议吗

更新

如果实例是“脏的”,我有DataTrigger将模板的背景设置为黄色。就目前而言,如果我只是补充 IsDirty=true
对于属性设置器,模板将始终具有黄色背景。我需要一种方法让模型忽略属性上的第一个初始化值。

加载Config.Schedules后,为什么不重置它

foreach (var sched in Config.Schedules)
     sched.IsDirty = false;

如果您真的不希望IsDirty设置为true,那么可以将IsDirty更改为可为null的bool,如果IsDirty为null,则不更新属性设置器中的IsDirty。在加载Config.Schedules之后,您仍然需要在某个时刻设置IsDirty=false,以表明您希望IsDirty现在在属性设置程序中更新,为什么不直接重置它呢

foreach (var sched in Config.Schedules)
     sched.IsDirty = false;

如果您真的不希望IsDirty设置为true,那么可以将IsDirty更改为可为null的bool,如果IsDirty为null,则不更新属性设置器中的IsDirty。您仍然需要在某个时刻设置IsDirty=false,以表示您希望IsDirty现在在属性设置器中更新

我可能错了,但要绑定该对象,它必须已经实例化,不是吗?所以,也许可以更准确地解释一下自己:在加载Config.Schedules之后,为什么不重新设置它呢?foreach(Config.Schedules中的var sched)sched.IsDirty=false;如果您真的不希望IsDirty设置为true,那么可以将IsDirty更改为可为null的bool,如果IsDirty为null,则不更新属性设置器中的IsDirty。您仍然需要在某个时刻设置IsDirty=false,以表明您希望IsDirty现在在属性设置器中被更新。便宜又脏,请使用加载后设置的bool标志。没有“解决方案”。@J.H把它写下来作为一个答案,这样我就可以给你一个信用。我可能错了,但要绑定那个东西,它已经被实例化了,不是吗?所以在你同意之后,也许可以更准确地解释你自己