【问题标题】:RaisePropertyChanged Triggering "set" On Different PropertyRaisePropertyChanged 在不同的属性上触发“设置”
【发布时间】:2018-09-24 15:29:05
【问题描述】:

当我在 MVVM Light 中遇到 RaisePropertyChanged 问题时,我正在处理一个我似乎无法弄清楚的问题。当我尝试为我的列表提出更改时,列表确实会更新,但上面选定的索引值也是如此。传递给我选择的索引的值似乎受按下哪个键来触发事件的影响(即,如果我按“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 处的项目执行此操作,但只要按下某个键并到达 RaisePropertyChanged() 区域,任何其他索引都会自动更改为 0。

【问题讨论】:

  • 你能分享一下 xaml 部分吗?
  • 您不需要为 ItemsSource 绑定 RaisePropertyChanged("TestList") 或 UpdateSourceTrigger=PropertyChanged - 列表永远不会更改值。
  • 对不起,我忘了说,在实际程序中,也可以在用户界面中添加和删除列表。但是该功能按预期工作,因此我没有将其包含在此处。

标签: c# wpf mvvm mvvm-light


【解决方案1】:

检查下面的代码是否符合您的要求。

使用ComboBoxSelectedItem 属性并将选定项绑定到编辑屏幕/文本框。我在这里绑定了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));
        }
    }
}

【讨论】:

  • 谢谢。 DisplayMemberPath 是我需要的。没想过使用它,反而让一切变得过于复杂。
【解决方案2】:

对于此示例,您甚至不需要 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; }
   }
}

除非需要选定Itemindex,否则没有真正的论据反对简单地将每个项目公开为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>

正常

在每次击键后更新可能会降低性能,并且它会剥夺用户在提交新值之前退格和修复输入错误的通常机会see MS reference

但是,只有在更新源时发生其他处理时,这才是一个问题。如果您担心所涉及的处理量,您可以通过简单地省略 `UpdateSourceTrigger' 声明来切换到 LostFocus 的默认行为。

【讨论】:

    猜你喜欢
    • 2020-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-30
    • 1970-01-01
    • 2014-10-07
    • 2013-04-09
    相关资源
    最近更新 更多