WP7 Toolkit - Как можно игнорировать такие события, как «SelectionChanged» в ListPicker и «Checked» в ToggleSwitch, когда они изменяются кодом (не вводится пользователем)? - PullRequest
5 голосов
/ 12 января 2012

Я новичок в XAML и C #, но мне нравилось работать с ним в течение нескольких недель, когда я играл с ним.Я начал работать над приложением и собрал простую страницу «Настройки» в XAML;теперь я пытаюсь подключить события к элементам управления, чтобы (а) обновить состояние приложения, когда пользователь взаимодействует с ними, и (б) иметь текущее состояние при посещении страницы.

Я нажал два(связанные) дорожные блоки, хотя:

  • набор инструментов: элемент управления ListPicker, кажется, не работает должным образом, когда я определяю «ListPickerItem» в XAML, поэтому в конструкторе SettingsPage яустановите содержимое вручную:

    lpColour.ItemsSource = new List<string>()
    {
        "Red","Blue","Green","Custom…"
    };
    lpColour.SelectedIndex = 1;  // set the currently selected item to "Blue"
    

    Однако, поскольку у элемента управления (в этом примере lpColour) есть событие на SelectionChanged, два события запускаются (одно с выбранным «Red» в качестве поля заполнено, затем другоекогда выбран "синий").Я не хочу обрабатывать «SelectionChanged» в данный момент;только когда пользователь взаимодействует с самим элементом управления (например, если он выбирает «Пользовательский…»), я могу открыть отдельное текстовое поле и выделить его; но я не хочу этого делать, когда настраиваюстраницу, и у них ранее был выбран «Пользовательский…», иначе пользователь получит клавиатуру, появляющуюся, как только он откроет страницу настроек ...)

  • Аналогично, я обнаружил, что элементы управления ToggleSwitch будутзапускать события "Checked" и "Unchecked", когда свойство IsChecked изменяется на что-то новое.Опять же, есть ли способ игнорировать или подавлять это событие при изменении кода?(Я вроде как обошел это сейчас, просто используя «Clicked», но с точки зрения обучения было бы неплохо знать, как с этим справиться).

Я думал, может бытьбыл какой-то способ получить «происхождение» (например, «код» или «пользовательский ввод») события из «SelectionChangedEventArgs» или «RoutedEventArgs» ... но, возможно, нет?

Я также пыталсяустановка «инициализированного» значения bool (по умолчанию «false», после запуска конструктора установите «true») и оберните код обработки событий в что-то вроде «if (initialized) {...}»; но событие по-прежнемупохоже, что он был запущен после того, как конструктор был создан для кода "lpColour.ItemSource = ..." и "lpColour.SelectedIndex = 1", который был выполнен, пока "initialized" был "false". Очень странно.: P

Надеюсь, я объясняю это ясно - я никогда не писал здесь раньше!

Буду признателен за любую помощь, которую вы можете предложить. Спасибо!

ОБНОВЛЕНИЕ - благодаря ответу @ MyKuLLSKI, это прекрасное место для работы.

В качестве примечания, опираясь на эту идею, я попытался сохранить их как «List's первоначально» и иметь «IgnoreSelectionChanged» в виде целого числа, которое будет «обратным отсчетом» (поэтому перед установкой ItemSource ListPicker я бы установил «IgnoreSelectionChanged + = 2»"(чтобы учесть два события, которые будут уволены);Точно так же я бы установил «IgnoreSelectionChanged ++» непосредственно перед установкой SelectedIndex вручную ... это, похоже, тоже работает.

Однако использование «ObservableCollection», привязанного к ListPicker, и полагаться на это, чтобы сообщить об изменениях, кажется, возможнолучший способ, чем использовать собственное событие ListPicker «SelectionChanged», поэтому я изменю свой код, чтобы использовать его вместо этого.

Еще раз спасибо!

1 Ответ

6 голосов
/ 12 января 2012

Я постараюсь ответить на все ваши вопросы / проблемы

  1. Причина, по которой у вас возникают проблемы при настройке ItemSource в XAML, заключается в том, что я почти уверен, что у вас есть проблемы с привязкой.Для работы привязок необходимо иметь DataContext и привязку для элемента UIElement.

  2. Что-то, что покупается для свойства, должно быть DependencyProperty или INotifyPropertyChanged

  3. Также List не является хорошим типом Collection для привязки ListPicker.Вместо этого вы, вероятно, захотите использовать вместо него ObservableCollextion ().Это если эта коллекция привязана к ListPicker и элементы, изменяющие ListPicker, будут автоматически обновлены.

  4. Причина, по которой событие SelectionChanged вызывается 2 раза, состоит в том, что вы меняли его дважды.Когда ListPicker создается впервые, выбранный элемент имеет значение null или -1, поскольку в нем нет элементов.Затем, когда вы устанавливаете ItemSource, он автоматически изменяет SelectedIndex на 0, затем вы меняете его на 1.

  5. Один из способов - добавлять флаг каждый раз, когда пользователь, которого вы знаете, изменяет переменную вкод

  6. В Silverlight отсутствует свойство IsLoaded, поэтому вы можете добавить bool, когда страница загружается в значение true.

  7. Когда привязка не выполняетсяизменить свойство в UIElement.Вместо этого измените свойство, с которым оно связано.

Ниже приведено мое решение, которое должно решить все ваши проблемы (WP7.1):

XAML

  <phone:PhoneApplicationPage 
       x:Class="WP7Sandbox.MainPage"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
       xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
       DataContext="{Binding RelativeSource={RelativeSource Self}}"
       mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
       FontFamily="{StaticResource PhoneFontFamilyNormal}"
       FontSize="{StaticResource PhoneFontSizeNormal}"
       Foreground="{StaticResource PhoneForegroundBrush}"
       SupportedOrientations="Portrait" Orientation="Portrait"
       shell:SystemTray.IsVisible="True"
       Loaded="PhoneApplicationPageLoaded">

    <Grid>
        <StackPanel>
            <toolkit:ListPicker ItemsSource="{Binding ListPickerCollection, Mode=TwoWay}" SelectionChanged="ListPickerSelectionChanged" SelectedIndex="{Binding ListPickerSelectedIndex, Mode=TwoWay}"/>
            <Button Click="ButtonClick" Content="Selection Change and Ignore Event"/>
            <Button Click="Button2Click" Content="Selection Change and Trigger Event"/>

            <toolkit:ToggleSwitch IsChecked="{Binding ToggleSwitchValue, Mode=TwoWay}"/>
        </StackPanel>
    </Grid>
</phone:PhoneApplicationPage>

Код позади

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Phone.Controls;

namespace WP7Sandbox
{
    public partial class MainPage : PhoneApplicationPage, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

        }

        private bool IsLoaded;

        private bool IgnoreSelectionChanged;

        public ObservableCollection<string> ListPickerCollection { get; private set; }

        private bool _ToggleSwitchValue;
        public bool ToggleSwitchValue
        {
            get
            {
                 return _ToggleSwitchValue;
            }

            set
            {

                _ToggleSwitchValue = value;
                OnPropertyChanged("ToggleSwitchValue");
            }
        }

        private int _ListPickerSelectedIndex;
        public int ListPickerSelectedIndex
        {
            get
            {
                return _ListPickerSelectedIndex;
            } 

            set
            {
                _ListPickerSelectedIndex = value;
                OnPropertyChanged("ListPickerSelectedIndex");
            }
        }

        public MainPage()
        {
            InitializeComponent();

            ListPickerCollection = new ObservableCollection<string>()
            {
                "Red",
                "Blue",
                "Green",
                "Custom…"
            };
        }

        private void PhoneApplicationPageLoaded(object sender, RoutedEventArgs e)
        {
            IsLoaded = true;
        }

        private void ListPickerSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (IsLoaded && !IgnoreSelectionChanged)
            {
            }

            IgnoreSelectionChanged = false;
        }

        private void ButtonClick(object sender, RoutedEventArgs e)
        {
            // I want to ignore this SelectionChanged Event
            IgnoreSelectionChanged = true;
            ChangeListPickerSelectedIndex();
        }

        private void Button2Click(object sender, RoutedEventArgs e)
        {
            // I want to trigger this SelectionChanged Event
            IgnoreSelectionChanged = false; // Not needed just showing you
            ChangeListPickerSelectedIndex();
        }

        private void ChangeListPickerSelectedIndex()
        {
            if (ListPickerSelectedIndex - 1 < 0)
                ListPickerSelectedIndex = ListPickerCollection.Count - 1;

            else
                ListPickerSelectedIndex--;
        }
    }
}

Многое есть, но оно должно помочь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...