我基于官方的Microsoft示例来创建 MasterDetail ListView : MasterDetail ListView UWP sample
我已根据我的情况调整了它,因为我希望用户可以直接编辑ListView 中的所选项目。但我遇到了一个奇怪的竞争对手:
我的 ListView 的XAML是这样的:
<!-- Master : List of Feedbacks -->
<ListView
x:Name="MasterListViewFeedbacks"
Grid.Row="1"
ItemContainerTransitions="{x:Null}"
ItemTemplate="{StaticResource MasterListViewFeedbacksItemTemplate}"
IsItemClickEnabled="True"
ItemsSource="{Binding CarForm.feedback_comments}"
SelectedItem="{Binding SelectedFeedback, Mode=TwoWay}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.FooterTemplate>
<DataTemplate>
<CommandBar Background="White">
<CommandBar.Content>
<StackPanel Orientation="Horizontal">
<AppBarButton Icon="Add" Label="Add Feedback"
Command="{Binding AddItemFeedbacksCommand}" />
<AppBarButton Icon="Delete" Label="Delete Feedback"
Command="{Binding RemoveItemFeedbacksCommand}" />
</StackPanel>
</CommandBar.Content>
</CommandBar>
</DataTemplate>
</ListView.FooterTemplate>
</ListView>
ListView的ItemTemplate 的XAML是:
<DataTemplate x:Key="MasterListViewFeedbacksItemTemplate" x:DataType="models:Feedback_Comments">
<StackPanel Margin="0,11,0,13"
Orientation="Horizontal">
<TextBlock Text="{x:Bind creator }"
Style="{ThemeResource BaseTextBlockStyle}" />
<TextBlock Text=" - " />
<TextBlock Text="{x:Bind comment_date }"
Margin="12,1,0,0" />
</StackPanel>
</DataTemplate>
详细信息容器的XAML如下所示:
<!-- Detail : Selected Feedback -->
<ContentPresenter
x:Name="DetailFeedbackContentPresenter"
Grid.Column="1"
Grid.RowSpan="2"
BorderThickness="1,0,0,0"
Padding="24,0"
BorderBrush="{ThemeResource SystemControlForegroundBaseLowBrush}"
Content="{x:Bind MasterListViewFeedbacks.SelectedItem, Mode=OneWay}">
<ContentPresenter.ContentTemplate>
<DataTemplate x:DataType="models:Feedback_Comments">
<StackPanel Visibility="{Binding FeedbacksCnt, Converter={StaticResource CountToVisibilityConverter}}">
<TextBox Text="{Binding creator, Mode=TwoWay}" />
<DatePicker Date="{Binding comment_date, Converter={StaticResource DateTimeToDateTimeOffsetConverter}, Mode=TwoWay}"/>
<TextBox TextWrapping="Wrap" AcceptsReturn="True" IsSpellCheckEnabled="True"
Text="{Binding comment, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ContentPresenter.ContentTemplate>
<ContentPresenter.ContentTransitions>
<!-- Empty by default. See MasterListView_ItemClick -->
<TransitionCollection />
</ContentPresenter.ContentTransitions>
</ContentPresenter>
“ CarForm ”是我的ViewModel的主要对象。每个CarForm都包含一个“ Feedback_Comments ”列表。
所以在我的 ViewModel 中,我在添加新评论时执行此操作:
private void AddItemFeedbacks()
{
FeedbacksCnt++;
CarForm.feedback_comments.Add(new Feedback_Comments()
{
sequence = FeedbacksCnt,
creator_id = user_id,
_creator = username,
comment_date = DateTime.Now
});
SelectedFeedback = CarForm.feedback_comments[CarForm.feedback_comments.Count - 1];
}
=&GT;在添加之前编辑的Feedback_Comment中完成的更改保存得很好
当用户选择现有的Feedback_Comment时,我什么都不做:这是由XAML直接管理的。
=&GT;在修改之前编辑的Feedback_Comment中所做的更改未保留
=&GT;你有任何解释吗?
答案 0 :(得分:1)
仅当TwoWay
失去焦点时,Text
属性的TextBox
绑定才会更新。但是,当您在列表中选择其他项目时,TextBox
的内容不再绑定到原始项目,因此不会更新。
要在Text
内容每次更改时触发更新,以便立即反映更改,请将UpdateSourceTrigger
设置为PropertyChanged
:
<TextBox Text="{Binding comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
为确保您的更改在包括列表在内的所有地方得到重新设置,您需要做两件事。
首先,您的feedback_comments
类型为ObservableCollection<Feedback_Comments>
。这样可以确保添加和删除已添加和删除的项目ListView
。
其次,Feedback_Comments
类必须实现INotifyPropertyChanged
接口。需要此接口才能让用户界面了解数据绑定对象属性的更改。
实现此接口非常简单,并且描述为for example on MSDN。
快速解决方案如下所示:
public class Feedback_Comments : INotifyPropertyChanged
{
// your code
//INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged( [ CallerMemberName ]string propertyName = "" )
{
PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( propertyName ) );
}
}
现在,每个属性设置器在设置值后调用OnPropertyChanged();
:
private string _comment = "";
public string Comment
{
get
{
return _comment;
}
set
{
_comment = value;
OnPropertyChanged();
}
}
请注意,[CallerMemberName]
属性告诉编译器将参数替换为调用者的名称 - 在本例中是属性的名称,这正是您所需要的。
另请注意,在这种情况下您无法使用简单的自动属性(因为您需要调用OnPropertyChanged
方法。
最后作为一个小推荐,我发现你使用的是C ++ - 就像命名约定一样,它不适合C#世界。请查看recommended C# naming conventions以提高代码可读性:-)。