【发布时间】:2017-08-10 03:49:22
【问题描述】:
更新:
这似乎是两个独立的绑定,一个在内存中的对象和 GridView 之间,一个在内存中的对象和文本框之间。
文本框将更改传播回内存中的对象,但这些更改无法反映在 GridView 的显示中。
原文:
我一直在做一些研究并尝试了一些不同的技术,但我无法更新我的网格视图。目标是让 GridView 显示项目图块列表,数据绑定到 ObservableCollection。在同一页面上的 GridView 下方,是一个用于编辑 GridView 中的项目的表单。当用户在 GridView 中选择一个项目时,表单的文本框(和其他控件)会自动填充 GridView 中所选项目的属性值。修改控件的值然后更改所选 GridView 项的属性值。
我有一个会议数据类型,其中包括一个名称属性(字符串类型)。 “会议”是 ObservableCollection 类型。
gridview 看起来像这样(为简洁起见,此处省略了一些属性):
<GridView Style="{StaticResource HorizontalScrollGridView}"
Name="ConferencesGridView"
ItemsSource="{Binding Conferences, Mode=TwoWay}"
SelectionChanged="ConferencesGridView_SelectionChanged">
在 GridView 内部,是一个如下所示的项目模板:
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:Conference">
<Grid Height="150"
Width="150">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"></TextBlock>
<TextBlock Grid.Row="1"
Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
TextWrapping="WrapWholeWords"></TextBlock>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
请注意,正确定义了 XML 命名空间“数据:”以引用定义“会议”数据类型的命名空间。没有编译错误,只有在程序运行时出现意外(或在这种情况下完全丢失)行为。
最后,在同一页面上,但不在 GridView 内,是用于编辑当前选定项目的表单。它包括如下文本框:
<TextBox Name="ConferenceNameTextBox"
Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
TextChanged="ConferenceNameTextBox_TextChanged"></TextBox>
文本框的 DataContext 是在 GridView 的 SelectionChanged 事件处理程序中以编程方式设置的:
ConferenceNameTextBox.DataContext = (Conference)ConferencesGridView.SelectedItem;
现在,在文本框的 TextChanged 事件处理程序中,以下代码行修改了 GridView 中选定项的属性(我知道使用 TextChanged 代替 LostFocus 会影响性能,但我会解决在我得到基本概念之后):
((Conference)ConferencesGridView.SelectedItem).Name = ConferenceNameTextBox.Text;
所以,在运行时,我会在 GridView 中选择不同的项目。那里没有问题;文本框的值会相应更新,显示当前选中的 GridView 项的名称值。
我更改了文本框中的文本,并且该文本成功更新了 GridView 用作源的项目。我通过在 GridView 中选择不同的项目,然后返回选择已编辑的项目,以及导航到框架内的不同 XAML 页面,然后返回到它被编辑的页面来验证这一点。编辑后的值被保留。
但是,当文本框的文本值更新时,GridView 的项目模板中显示的文本不会更新。 GridView 仅在重新加载 XAML 页面时更新(导航离开然后返回到它所在的框架中)。
我通过研究发现 ObservableCollection 足以从源中添加和删除项目(实际上这样做确实会更新 GridView),但这不足以更改源中列表项的属性.
我看到在源对象(在本例中为会议对象)上实现 INotifyPropertyChanged 是必要的。我已经这样做了。我还阅读了有关需要将文本框双向绑定到数据源的信息。我也试过了,没有成功:
public class Conference : INotifyPropertyChanged
{
public string Name { get; set; }
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
// Raise the PropertyChanged event, passing the name of the property whose value has changed.
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
在 ASP.NET 中,我记得在编辑数据源中的数据后调用 GridView.DataBind(),这会刷新 GridView。不过,XAML 中似乎没有等价物。
我猜测缺少某些东西,或者我没有正确的组件组合。综上所述:
当文本框(位于 GridView 外部,用于编辑 GridView 中所选项目的 Name 属性)值时,如何获取 GridView 显示的项目(包括显示项目的 Name 属性)进行更新变化?
【问题讨论】:
-
您可以尝试重新加载源代码吗?即,以编程方式将源设置为空,然后返回正确的源。这可能有点草率,但我相信这可能是最简单的解决方法。
-
这是一个更普遍的问题,可能无法解决您的问题,但是...您应该避免使用 EventHandlers,尤其是当 - 在这种情况下 - 您可以在您已经绑定到的属性。此外,您可以考虑将
SelectedItem属性绑定到代码中的单独属性,然后绑定到该属性而不是依赖于数据上下文,而不是以编程方式更改数据上下文。这至少会让你的代码更容易预测/更容易阅读。 -
我尝试以编程方式设置源,但这会破坏结果。 @SteffenWinkler,你能举个例子来说明你在说什么吗?我想我明白你的意思是:在 XAML 页面上创建一个属性,该属性绑定到(并因此填充)gridview 中当前选定的项目,然后将文本框绑定到那个…但我不是确定如何去做。
-
您将
SelectionChanged="ConferencesGridView_SelectionChanged"替换为SelectedItem={Binding SelectedConference, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged},然后将private Conference selectedConference; public Conference SelectedConference{get{return selectedConference;}set{selectedConference=value;this.PropertyChanged();}添加到包含您的数据网格绑定到的Conference对象集合的类中。 -
谢谢!我进行了建议的更改......但它并没有解决问题,并且它破坏了文本框和正在工作的内存对象之间的连接。不过,在事件上使用绑定的想法是有道理的。
标签: c# xaml gridview data-binding