MasterDetail ListView和可编辑的ContentPresenter:有什么问题?

时间:2016-11-11 17:06:33

标签: xaml listview binding uwp master-detail

我基于官方的Microsoft示例来创建 MasterDetail ListView MasterDetail ListView UWP sample

我已根据我的情况调整了它,因为我希望用户可以直接编辑ListView 中的所选项目。但我遇到了一个奇怪的竞争对手:

  • 当我向ListView添加新项时,在详细信息容器中完成的当前项的更改保存得好
  • 但当我在ListView中选择现有项目时,在详细信息容器中完成的当前项目的更改未保存

以下是我的应用的截图: screenshot

我的 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;你有任何解释吗?

1 个答案:

答案 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以提高代码可读性:-)。