如何使用 MVVM 模式更新 UWP 枢轴外观

How to update UWP pivot appearence using MVVM pattern

我正在使用 MVVM 模式开发 UWP 应用程序。 页面上有一个Pivot控件,这里是一个gist。它看起来像这样:

我需要突出显示数据透视元素 header 和列表元素,然后用户 select 给出答案。像这样:

而且我在更新枢轴 header 和子列表外观时遇到问题。 我尝试订阅不同的 Pivot 事件,如 LayoutUpdatedLoadedPivotItemLoaded 等,但这种方式并没有解决问题。

创建页面时,似乎所有的枢轴元素都加载了一次。 我已经实现 header 突出显示然后页面重新加载或重新导航,但这不是我需要的。

如何更新 Pivot header 外观和其他元素?

It seems like all pivot elements are loaded once when page is created. I have achieved that header highlights then page reloaded or renavigated, but this is not what I need. How can I update Pivot header appearence and other elements?

根据您的要求,您必须创建逻辑数据模型。

PivotHeaderDataContext是"Question"。因此,您可以在 Question class 中为 PivotHeader 创建 IsCheck 属性。而 listView 项目的 DataContext 是 "Answer"。所以你可以 'IsRightFlag' 属性 用于列表视图项。这是一个典型的三明治架构。

ViewModel.cs

public class MainPageViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    private ObservableCollection<Question> questions;
    public ObservableCollection<Question> Questions { get => questions; set => questions = value; }

    public MainPageViewModel()
    {
        questions = new ObservableCollection<Question>();
        this.Questions.Add(new Question { Text = "Hello This Nico !", QuestionNumber = "1", RightAnswer = new Answer { Text = "Nico" } });
        this.Questions.Add(new Question { Text = "Hello This Sunteen !", QuestionNumber = "2", RightAnswer = new Answer { Text = "Sunteen" } });
        this.Questions.Add(new Question { Text = "Hello This Lidong !", QuestionNumber = "3", RightAnswer = new Answer { Text = "Lidong" } });
    }
} 

Question.cs

public class Question : INotifyPropertyChanged
    {
        public string QuestionNumber { get; set; }
        public string Text { get; set; }
        public Answer RightAnswer { get; set; }
        public ObservableCollection<Answer> Answers { get => answers; set => answers = value; }
        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        private ObservableCollection<Answer> answers;
        private Question CurrentQuestion;
        public event PropertyChangedEventHandler PropertyChanged;
        private Answer selectItem;
        public Answer SelectItem
        {
            get
            {
                return selectItem;
            }
            set
            {
                selectItem = value;

                if (selectItem.Text == CurrentQuestion.RightAnswer.Text)
                {
                    selectItem.IsRightFlag = true;
                    IsCheck = true;
                }
                else
                {
                    selectItem.IsRightFlag = false;
                    IsCheck = false;
                }
                OnPropertyChanged();
            }
        }
        private bool isCheck;
        public bool IsCheck
        {
            get
            {
                return isCheck;
            }
            set
            {
                isCheck = value;
                OnPropertyChanged();
            }
        }
        public ICommand ItemCommand
        {
            get
            {
                return new CommadEventHandler<Question>((item) => ItemClick(item));
            }
        }
        private void ItemClick(Question item)
        {
            this.CurrentQuestion = item;
        }
        public Question()
        {
            answers = new ObservableCollection<Answer>();
            Answers.Add(new Answer { Text = "Lidong" });
            Answers.Add(new Answer { Text = "Nico" });
            Answers.Add(new Answer { Text = "Sunteen" });
            Answers.Add(new Answer { Text = "Who ?" });
        }
    }

Answer.cs

public class Answer : INotifyPropertyChanged
{
    public string Text { get; set; }
    private bool isRigntFlag;
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    public bool IsRightFlag
    {
        get
        {
            return isRigntFlag;
        }
        set
        {
            isRigntFlag = value;
            OnPropertyChanged();
        }
    }
}

MainPage.xaml

<Page.DataContext>
    <local:MainPageViewModel/>
</Page.DataContext>
<Page.Resources>
    <local:WaringConverter x:Key="converter"/>
    <DataTemplate x:Key="AnswerListDataTemplate">
        <Border Margin="5" BorderThickness="2" BorderBrush="White" Background="Transparent"
                DataContext="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Content}">
            <TextBlock 
                Margin="10" 
                FontSize="28" 
                TextWrapping="WrapWholeWords" 
                Text="{Binding Text}"
                Foreground="{Binding IsRightFlag, Converter={StaticResource converter},Mode=TwoWay}"/>
        </Border>
    </DataTemplate>
    <DataTemplate x:Key="PivotQuestionDataTemplate">
        <StackPanel Orientation="Vertical">
            <TextBlock FontSize="28" Margin="20" TextWrapping="WrapWholeWords" Text="{Binding Text}"/>
            <ListView Grid.Row="2" Margin="0,10" IsItemClickEnabled="True"                  
                          ItemsSource="{Binding Answers}"  
                          SelectedItem="{Binding SelectItem,Mode=TwoWay}"
                          ItemTemplate="{StaticResource AnswerListDataTemplate}"
                      >
                <i:Interaction.Behaviors>
                    <ic:EventTriggerBehavior EventName="ItemClick">
                        <ic:InvokeCommandAction  Command="{Binding ItemCommand}" CommandParameter="{Binding}" />
                    </ic:EventTriggerBehavior>
                </i:Interaction.Behaviors>
            </ListView>
        </StackPanel>
    </DataTemplate>
    <DataTemplate x:Key="PivotHeaderDataTemplate">
        <Border Padding="5" BorderThickness="2" BorderBrush="Gray" Background="{Binding IsCheck ,Converter={StaticResource converter},Mode=TwoWay}">
            <TextBlock FontSize="24" >
                <Run x:Uid="QuestionsPage/QuestionNumber"/>
                <Run Text="{Binding QuestionNumber}"/>
            </TextBlock>
        </Border>
    </DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid Margin="30,50,30,10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Text=""/>
        <Pivot Grid.Row="2"
               x:Name="pivotControl"

               ItemsSource="{Binding Questions}" 
               ItemTemplate="{StaticResource PivotQuestionDataTemplate}"
               HeaderTemplate="{StaticResource PivotHeaderDataTemplate}" 
               >
        </Pivot>
    </Grid>
</Grid>

WaringConverter.cs

public class WaringConverter :IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if((bool)value == true)
            {
                return new SolidColorBrush(Colors.Green);
            }
            else
            {
                return new SolidColorBrush(Colors.Gray);
            }  
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }