Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何提高不同模型的属性更改_C#_Wpf_Binding_Datagrid - Fatal编程技术网

C# 如何提高不同模型的属性更改

C# 如何提高不同模型的属性更改,c#,wpf,binding,datagrid,C#,Wpf,Binding,Datagrid,我有以下问题:我的WPF应用程序使用DataGrid来显示任务列表。这些任务存储在SQL数据库中,我们使用实体框架。为了提高可读性,任务的简化模型位于问题的末尾。任务模型已分配类别对象。所有类别都存储在数据库中,在本问题的末尾还可以看到类别模型 该类别在DataGrid中显示为组合框,因此您可以选择: <Window.Resources> <CollectionViewSource x:Key="categoryViewSource" d:DesignSourc

我有以下问题:我的WPF应用程序使用DataGrid来显示任务列表。这些任务存储在SQL数据库中,我们使用实体框架。为了提高可读性,任务的简化模型位于问题的末尾。任务模型已分配类别对象。所有类别都存储在数据库中,在本问题的末尾还可以看到类别模型

该类别在DataGrid中显示为组合框,因此您可以选择:

<Window.Resources>    
    <CollectionViewSource x:Key="categoryViewSource" d:DesignSource="{d:DesignInstance {x:Type Models:Category}, CreateList=True}"/>
    <CollectionViewSource x:Key="taskViewSource" d:DesignSource="{d:DesignInstance {x:Type Models:Task}, CreateList=True}"/>
</Window.Resources>
<DataGrid DataContext="{StaticResource taskViewSource}" ItemsSource="{Binding}" EnableRowVirtualization="True">
    <DataGrid.Columns>
        [DataGridTemplateColumn => DataGrid.CellTemplate => DataTemplate and then:]
        <ComboBox x:Name="categoryValues" 
              IsSynchronizedWithCurrentItem="False"
              ItemsSource="{Binding Source={StaticResource categoryViewSource},
                    Mode=OneWay}"
              SelectedItem="{Binding Category,
                    Mode=TwoWay,
                    UpdateSourceTrigger=PropertyChanged}"/>
    </DataGrid.Columns>
</DataGrid>
这个很好用。但是,当我编辑类别时,允许编辑类别名称,问题就开始了。ItemsSource会相应地更新,因此在下拉菜单中,该值将以新名称显示。但是,SelectedItem的绑定不会得到更新。这意味着,所有已选择已编辑类别的组合框仍显示旧值

我发现如果我在更改值时这样做:

public void ChangeCategoryName(string name, Category c) 
{
    c.Name = name;
    foreach (var task in c.Tasks) 
    {
        task.Category = null;
        task.Category = c;
    }
}
然后立即在组合框的SelectedItem中更新该值。我的猜测是,当我更改类别中的值时,不会为任务调用PropertyChanged。我试着强迫大家这样做:

public virtual void OnPropertyChanged([CallerMemberName] String propertyName = "")
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    // Force Tasks to update
    this.Tasks?.ForEach(t =>
    {
        t.OnPropertyChanged("Category");
    });
}
那没用。有人知道怎么解决这个问题吗

这是我的模型的代码

namespace Application.Models 
{
    public class Task : INotifyPropertyChanged
    {
        [Key]
        public int TaskId { get; set; }

        [...]

        // Category is defined in anothre table
        public int? CategoryId { get; set; }
        [ForeignKey("CategoryId")]
        // The Category object will automatically be loaded if access is needed
        public virtual Category Category { get; set; }

        // PropertyChanged Event
        public event PropertyChangedEventHandler PropertyChanged;
        public virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    public class Category : INotifyPropertyChanged
    {
        [Key]
        public int CategoryId { get; set; }
        public string Name { get; set; }
        // List of Task objects that are associated to this Category object
        public virtual List<Task> Tasks { get; set; }

        // PorpertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        public virtual void OnPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public override string ToString()
        {
            return Name;
        }
    }
}

我发现了问题所在。请记住:使用自己的模板时,始终确保正确更新更改。在我的例子中,ComboBoxItem中的绑定依赖于DataContext:

<ControlTemplate x:Key="SimpleComboBoxItem">
    <StackPanel>
        <TextBlock Text="{Binding}" />
    </StackPanel>
</ControlTemplate>
因此,为了订阅PropertyChanged触发器,我显式添加了绑定路径:

<ControlTemplate x:Key="SimpleComboBoxItem">
    <StackPanel>
        <TextBlock Text="{Binding Name}" />
    </StackPanel>
</ControlTemplate>
我觉得自己很愚蠢,但我4周前就开始使用WPF了,以前从未使用过,突然间我成了WPF程序员。请原谅我的无礼

编辑


删除了一些不必要的绑定说明。多亏了埃德

我不确定你实际上改变了什么价值,应该产生什么影响,以及你的实体与另一个实体的关系。你能试着澄清你的问题吗?可能至少会显示一个屏幕截图,这样就可以清楚地知道,如果不想显示完整的XAML,哪些控件与之绑定。此外,由于此.Tasks似乎是一个集合,如果希望正确跟踪更改,您可能会对某个集合感兴趣。我猜,当我更改类别中的值时,不会为任务调用PropertyChanged。-正当你没有做任何可能导致这种情况发生的事情,所以它不会发生。如果类别需要在其属性更改时通知UI,则类别必须在每个属性上无例外地引发PropertyChanged,并且其任务必须是ObservableCollection。通常,OnPropertyChanged应该受到保护。通常,任何viewmodel都不应为不同的viewmodel引发PropertyChanged这些是viewmodel,而不是模型。如果您正试图这样做,请返回并确定导致您正试图解决的问题的错误设计决策。@poke我稍后将编辑该问题。我认为XAML已经足够了,我不想把它炸了。基本上,我想更改类别对象的名称,并在所有具有该类别对象的任务对象中引发PropertyChanged事件。@EdPlunkett好的,我现在解决了这个问题。部分要感谢你。我开始修改我所有的代码,以构建一个可工作的最小样本。我非常感谢你的时间和热情。我的问题可能非常愚蠢,我道歉。我还是新手,顺便说一句,你需要的是{Binding Name}-在这种特殊情况下,所有的UpdateSourceTrigger等标志都不是ops。
<ControlTemplate x:Key="SimpleComboBoxItem">
    <StackPanel>
        <TextBlock Text="{Binding}" />
    </StackPanel>
</ControlTemplate>
<ControlTemplate x:Key="SimpleComboBoxItem">
    <StackPanel>
        <TextBlock Text="{Binding Name}" />
    </StackPanel>
</ControlTemplate>