RaisePropertyChanged Триггерный «набор» для другого свойства - PullRequest
0 голосов
/ 24 сентября 2018

Я работал над проектом, когда натолкнулся на проблему с RaisePropertyChanged из MVVM Light, которую я не могу понять.Когда я пытаюсь вызвать изменение для своего списка, список обновляется, но так же, как и выбранное значение индекса выше.Значение, которое передается в выбранный мной индекс, похоже, зависит от того, какая клавиша была нажата, чтобы вызвать событие (т. Е. Если я нажму «BACKSPACE», значение, переданное в установщик, будет «-1», тогда как если я введу букву,передано значение «0»)

Я воссоздал проект, который чисто демонстрирует проблему.Ниже приведен основной бит логики, найденный в MainVeiwModel:

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        _testItems = new List<TestItem>()
        {
            new TestItem() { Name = "Test1" },
            new TestItem() { Name = "Test2" }
        };
    }

    public int SelectedIndex
    {
        get { return _selectedIndex; }
        set
        {
            _selectedIndex = value;
            RaisePropertyChanged("SelectedIndex");
            RaisePropertyChanged("SelectedText");
            RaisePropertyChanged("TestList");
        }
    }

    public string SelectedText
    {
        get
        {
            return _testItems[_selectedIndex].Name;
        }
        set
        {
            _testItems[_selectedIndex].Name = value;
            RaisePropertyChanged("TextList");
        }
    }

    public List<string> TextList
    {
        get
        {
            _textList = new List<string>();
            if (_testItems != null && _testItems.Count > 0)
            {
                foreach (TestItem item in _testItems)
                    _textList.Add(item.Name);
            }
            return _textList;
        }
        set { _textList = value; }
    }

    private int _selectedIndex;
    private List<string> _textList;
    private List<TestItem> _testItems;
}

Мой XAML:

<Window x:Class="RaisePropertyBug.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:RaisePropertyBug"
    mc:Ignorable="d"
    DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <ComboBox ItemsSource="{Binding TextList, UpdateSourceTrigger=PropertyChanged}"
              SelectedIndex="{Binding SelectedIndex, UpdateSourceTrigger=PropertyChanged}"
        HorizontalAlignment="Center" VerticalAlignment="Center"/>

    <TextBox Grid.Row="1" Text="{Binding SelectedText, UpdateSourceTrigger=PropertyChanged}"
        HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>

Для контекста: у меня есть ComboBox, в котором перечислены именаиз коллекции предметов у меня есть.Существует окно редактирования, где пользователи могут изменять имена и другие свойства этих элементов.Моя цель - обновить список ComboBox, когда пользователь редактирует значение.В моей реальной программе вы можете сделать это с элементом с индексом 0, но любой другой индекс автоматически изменится на 0, как только будет нажата клавиша и будет достигнута область RaisePropertyChanged ().

Ответы [ 2 ]

0 голосов
/ 24 сентября 2018

Вам даже не нужен INotifyPropertyChanged для этого примера.Я не совсем уверен в том, чего вы пытаетесь достичь, но этот код даст то, что я почерпнул из вашего поста.

<Window x:Class="RaisePropertyChangedExample.BindingExample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Correct View" Width="150" Height="80">
   <StackPanel Orientation="Vertical">
      <ComboBox ItemsSource="{Binding Items}"
                x:Name="ItemViews"
                HorizontalAlignment="Stretch" VerticalAlignment="Center" DisplayMemberPath="Name"/>
      <TextBox DataContext="{Binding SelectedItem, ElementName=ItemViews}" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
               HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
   </StackPanel>
</Window>

и вспомогательный код

using System.Windows;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace RaisePropertyChangedExample
{
   public partial class BindingExample : Window
   {
      public BindingExample()
      {
         InitializeComponent();
         DataContext = new BindingExampleViewModel();
      }
   }

   public class BindingExampleViewModel
   {
      public ObservableCollection<TestItemViewModel> Items { get; set; }
         = new ObservableCollection<TestItemViewModel>(new List<TestItemViewModel>
         {
            new TestItemViewModel {Name = "Test1"},
            new TestItemViewModel {Name = "Test2"}
         });
   }

   public class TestItemViewModel
   {
      public string Name { get; set; }
   }
}

Если толькосуществует некоторая потребность в index из выбранных Item, нет никаких реальных аргументов против простого представления каждого элемента в качестве модели представления TestItemViewModel и привязки других элементов управления непосредственно к самому выбранному элементу.Однако если другие элементы управления привязаны к элементам TestItemViewModel, то все равно не обязательно, что вам следует реализовать INotifyPropertyChanged в этой модели представления.

В следующем примере по-прежнему будет отображаться правильная информация при подключении к существующей ViewModel:

<Window x:Class="RaisePropertyChangedExample.BindingExample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Correct View" Width="150" Height="100">
   <StackPanel Orientation="Vertical">
      <ComboBox ItemsSource="{Binding Items}"
                x:Name="Combo"
                HorizontalAlignment="Stretch" VerticalAlignment="Center" DisplayMemberPath="Name"/>
      <Grid DataContext="{Binding SelectedItem, ElementName=Combo}">
         <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
         </Grid.RowDefinitions>
         <TextBox Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                  HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
         <Label Grid.Row="1" HorizontalAlignment="Stretch" Height="20" Content="{Binding Name}" />
      </Grid>
   </StackPanel>
</Window>

Обычно

Обновление после каждого нажатия клавиши можетснижает производительность и лишает пользователя обычной возможности вернуться на задний план и исправить ошибки ввода перед принятием нового значения . см. Справочник MS

, однако, это проблема только в том случае, если в результате обновления источника происходит другая обработка.Если вас беспокоит объем обработки, вы можете переключиться на стандартное поведение LostFocus, просто пропустив объявление UpdateSourceTrigger.

0 голосов
/ 24 сентября 2018

Проверьте ниже код, если он работает в соответствии с вашими требованиями.

Используйте SelectedItem свойство ComboBox и привяжите выбранный элемент к экрану редактирования / текстовому полю.Я связал SelectedTestItem.Name здесь.

Просмотр -

<Window x:Class="StackOverflow.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:StackOverflow"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <ComboBox ItemsSource="{Binding TestItems, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Name" SelectedValuePath="Name"
          SelectedItem="{Binding SelectedTestItem, UpdateSourceTrigger=PropertyChanged}"
    HorizontalAlignment="Center" VerticalAlignment="Center"/>

    <TextBox Grid.Row="1" Text="{Binding SelectedTestItem.Name, UpdateSourceTrigger=PropertyChanged}" Width="200"
    HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>

View.cs -

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private TestItem selectedTestItem;

    public TestItem SelectedTestItem
    {
        get { return selectedTestItem; }
        set
        {
            selectedTestItem = value;
            RaisePropertyChanged("SelectedTestItem");
        }
    }



    public List<TestItem> TestItems
    {
        get;
        set;

    }

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;

        var items = new List<TestItem>()
                {
                    new TestItem() { Name = "Test1" },
                    new TestItem() { Name = "Test2" }
                };

        TestItems = items;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string prop)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }
}
...