【问题标题】:UI doesn't update when changing selected item更改所选项目时 UI 不更新
【发布时间】:2018-11-15 17:37:55
【问题描述】:

我有一个ListBox,其ItemSource 绑定到我的PointStylesViewModel 中包含的PointStyleModel 对象集合。 PointStyleModel 类具有三个属性:大小、名称和颜色(颜色的类型为 GeoColor - 第三方库对象)。

TextBox 绑定到 Name 属性。 xceed 工具包IntegerUpDown 绑定到Size。 一个 xceed 工具包ColorPicker 绑定到颜色。

目前,每当用户选择列表中的新项目时,三个控件都会正确更新。但是,如果用户在 UI 中更改 IntegerUpDown 或 ColorPicker 的值,然后在列表中选择不同的项目,则 UI 不会显示正确的值。我不希望仅仅因为用户更改 UI 中的值而更新属性。 TextBox 绑定到 Name 工作正常。我尝试了各种绑定模式和 updatesourcetriggers,但都没有成功。

这是我的模型类:

public class PointStyleModel
{
    public int Size
    {
        get;
        set;
    }

    public string Name
    {
        get;
        set;
    }

    public GeoColor Color
    {
        get;
        set;
    }
}

这是我的视图模型:

public class PointStylesViewModel : ViewModelBase //using Fody's PropertyChangedInterface in the base class
{
    public ObservableCollection<PointStyleModel> PointStyles { get; set; } //the listbox is bound to this

    public PointStyleModel SelectedPointStyle { get; set; } //bound to the listboxe's selected item

    public string PointStyleName { get { return SelectedPointStyle.Name; } }

    public Color PointStyleColor
    {
        get
        {
            return Color.FromArgb(SelectedPointStyle.Color.AlphaComponent, SelectedPointStyle.Color.RedComponent, SelectedPointStyle.Color.GreenComponent, SelectedPointStyle.Color.BlueComponent); //Need to convert GeoColor to Color
        }
    }

    public int PointStyleSize { get { return SelectedPointStyle.Size; } }

    public PointStylesViewModel()
    {
        PointStyles = new ObservableCollection<PointStyleModel>();
        AddDefaultPointStyles(); //add some default styles

        SelectedPointStyle = PointStyles.First(); //select the first item in the list when starting up
    }
}

以下是我观点的相关部分:

<TabItem DataContext="{Binding Path=PointStylesViewModel, Source={StaticResource ViewModelLocator}}">
    <Grid>
        <ListBox ItemsSource="{Binding PointStyles}" SelectedItem="{Binding SelectedPointStyle}" DisplayMemberPath="Name"/>
        <TextBox Text="{Binding PointStyleName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
        <GroupBox Header="Paint">
            <Grid>
                <xctk:ColorPicker SelectedColor="{Binding Path=PointStyleColor, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" DisplayColorAndName="False" DisplayColorTooltip="True"/>
                <xctk:IntegerUpDown Value="{Binding PointStyleSize, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Maximum="20" Minimum="0" />
            </Grid>
        </GroupBox>
    </Grid>
</TabItem>

这是一个问题的例子:

首先我在列表框中选择一个项目。一切都正确填充。

现在我将只更改 UI 上的颜色大小:

然后我将从列表中选择另一个项目:

在第一张图片中,我选择了 RedSquare6,它使用我的 VM 中的 PointStyleColor 属性填充 ColorPicker。它从 SelectedPointStyle 的 Color 属性中获取该值。这很好用。

在第二张图片中,我从 ColorPicker 控件中选择了一种新颜色,在本例中为粉红色。这不应该改变任何属性。我只是在更改控件的颜色。 RedSquare6 的 Color 属性仍应为 Red。

在第三张图片中,我选择了 GreenSquare6。 ColorPicker 控件现在应该显示为绿色,但它保持为粉红色,并且我的 VM 中的 PointStyleColor getter 不再被命中。

Size IntegerUpDown 控件也是如此。

选择新颜色时,颜色选择器和 intupdown 没有更新。我注意到更改选择时没有命中属性。 PointStyleName 是。

编辑:这是我的 ViewModelBase:

using PropertyChanged;
using System.ComponentModel;

namespace WpfApp1.ViewModels
{
    /// <summary>
    /// A base model that fires Property Changed events as needed
    /// </summary>
    [AddINotifyPropertyChangedInterface]
    public class ViewModelBase : INotifyPropertyChanged
    {
        /// <summary>
        /// The event is fired when any child property changes its value
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
    }
}

这是正在发生的事情的 GIF。我在这里测试 intupdown 控件:

正如您在上面看到的,一旦我将 IntUpDown 的值更改为 8,它就会保持在该值,即使所选项目正在更改,这应该将值更改为 6。

编辑:这是一个显示问题的小示例应用程序: https://www.dropbox.com/s/l3gu3nj915cstoa/TestApp.zip?dl=0

【问题讨论】:

  • 据我所见,没有任何东西在调用 PointStyleSizePointStyleColor。当SelectedPointStyle 改变时,没有逻辑告诉界面改变颜色或大小。
  • 你是对的。你是否知道,在使用 Fody 的 propertychanged 时,如何通知其他属性的变化?

标签: c# wpf mvvm data-binding xceed


【解决方案1】:

首先你需要在 ViewModelBase 中正确实现 INotifyPropertyChanged。

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

第二次需要在PointStylesViewModel上更改的选定Item上使用它:

private PointStyleModel _selectedPointStyle;
public PointStyleModel SelectedPointStyle
{
    get => _selectedPointStyle;
    set
    {
        _selectedPointStyle = value;
        OnPropertyChanged();
        OnPropertyChanged(nameof(PointStyleColor)); 
        OnPropertyChanged(nameof(PointStyleSize)); 
    }
 }

【讨论】:

  • 将其更改为 TwoWay 时出现此错误:System.Windows.Markup.XamlParseException: ''Set property 'Xceed.Wpf.Toolkit.ColorPicker.SelectedColor' 引发异常。'行号“192”和行位置“59”。内部异常 nvalidOperationException:TwoWay 或 OneWayToSource 绑定无法在“WpfApp1.ViewModels.PointStylesViewModel”类型的只读属性“PointStyleColor”上工作。
  • 我不想改变模型下面的属性值。用户不应该能够从 UI 更改任何属性。
  • 你想让 UI 颜色改变什么?
  • 因此用户可以更改 UI 上颜色选择器控件的颜色,但这不应更改“PointStyleColor”。当用户从列表框中选择一个新项目时,颜色选择器控件应该更新,但它与用户更改为的最后一个颜色保持相同。这仅在用户从颜色选择器中选择新颜色时才会发生,否则它会起作用。
  • 我很困惑你想要什么。你认为设定的颜色应该去哪里? ViewModel 上的不同属性?
猜你喜欢
  • 1970-01-01
  • 2020-12-29
  • 2016-10-02
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 2021-08-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多