简体   繁体   English

WPF Combobox 在视图模型中的绑定属性更新时视图未更新

[英]WPF Combobox in view not updating when bound property in viewmodel updated

I have a Combobox in a view, bound to a viewmodel with an ObservableCollection of a custom class of mine.我在视图中有一个 Combobox,绑定到一个视图模型,该视图模型具有我的自定义 class 的 ObservableCollection。 This custom class is simply a wrapper for an Enum which holds the value, and a string which is the enum description attribute.这个自定义的 class 只是一个包含值的枚举的包装器,以及一个作为枚举描述属性的字符串。 The combobox sets the DisplayMemberPath property to this name property, to display a more human readable description attribute value, rather than the enum itself combobox 将 DisplayMemberPath 属性设置为此名称属性,以显示更易于阅读的描述属性值,而不是枚举本身

I am finding that when I set the ItemsSource of the combobox to a collection of these Enum wrapper classes, and then set the SelectedItem property to one of these items, the combobox is not updating in the UI when I start my application.我发现当我将 combobox 的 ItemsSource 设置为这些枚举包装类的集合,然后将 SelectedItem 属性设置为这些项目之一时,当我启动我的应用程序时,combobox 不会在 UI 中更新。 If I change this to a List of strings, it seems to work.如果我将其更改为字符串列表,它似乎可以工作。

Here is my combobox:这是我的 combobox:

    <ComboBox
        DisplayMemberPath="Name"
        IsEditable="False"
        IsReadOnly="True"
        ItemsSource="{Binding SelectableTags}"
        SelectedItem="{Binding SelectedTag, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

My custom class the combobox is bound to a collection of:我的自定义 class combobox 绑定到以下集合:

public class EnumNamePair : ObservableObject
{
    private string name;
    public string Name
    {
        get => name;
        set => SetProperty(ref name, value);
    }

    private Enum enumValue;
    public Enum EnumValue
    {
        get => enumValue;
        set
        {
            SetProperty(ref enumValue, value);
            Name = enumValue.GetEnumDescription();
        }
    }

    public EnumNamePair(Enum enumValue)
    {
        EnumValue = enumValue;
    }
}

Part of my viewmodel:我的视图模型的一部分:

private ObservableCollection<EnumNamePair> selectableTags = new();
public ObservableCollection<EnumNamePair> SelectableTags
{
    get => selectableTags;
    set => SetProperty(ref selectableTags, value);
}

private EnumNamePair selectedTag;
public EnumNamePair SelectedTag
{
    get => selectedTag;
    set => SetProperty(ref selectedTag, value);
}

public TaggingRuleViewModel(string tag)
{
    SelectableTags = new List<EnumNamePair>(
        Enum.GetValues(typeof(AllowedTag)).Cast<AllowedTag>().Select(x => new EnumNamePair(x)));

    SelectedTag = SelectableTags.First(x => x.EnumValue.ToString() == tag),
}

This is simplified but recreates the problem.这是简化的,但会重现问题。 I have tried various additional raisings of OnPropertyChanged for my bound properties, altering the Readonly/Editable property setters on the combobox, dumbing down my viewmodels/custom class (it used to have a single getter for the name property rather than set on setting the EnumValue etc).我已经为我的绑定属性尝试了 OnPropertyChanged 的各种额外提升,更改了 combobox 上的只读/可编辑属性设置器,降低了我的视图模型/自定义 class(它曾经有一个用于 name 属性的 getter,而不是设置 EnumValue ETC)。 All that seems to work is changing the list of my custom class to a list of strings, and handling the conversion in the viewmodel.似乎所有的工作是将我的自定义 class 列表更改为字符串列表,并在视图模型中处理转换。 I know there are other ways of handling showing an enum description attribute in a combobox but at this point I simply want to know why this doesn't work.我知道还有其他方法可以处理在 combobox 中显示枚举描述属性,但此时我只是想知道为什么这不起作用。

Converter implementation example:转换器实现示例:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Core2022.SO.JosephWard
{
    public static class EnumExtensions
    {
        private static readonly Dictionary<Type, Dictionary<string, string>> enums
            = new Dictionary<Type, Dictionary<string, string>>();
        public static string GetEnumDescription<T>(this T value)
            where T : Enum
        {
            Type enumType = value.GetType();
            if (!enums.TryGetValue(enumType, out Dictionary<string, string>? descriptions))
            {
                descriptions = enumType.GetFields()
                    .ToDictionary(
                        info => info.Name,
                        info => ((DescriptionAttribute?)info.GetCustomAttributes(typeof(DescriptionAttribute), false)?.FirstOrDefault())?.Description ?? info.Name);
                enums.Add(enumType, descriptions);
            }

            string name = value.ToString();
            if (descriptions.TryGetValue(name, out string? description))
            {
                return description;
            }
            else
            {
                throw new ArgumentException("UnexpectedValue", nameof(value));
            }
        }
    }
}
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace Core2022.SO.JosephWard
{
    [ValueConversion(typeof(Enum), typeof(string))]
    public class EnumToDescriptionConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is Enum @enum)
                return @enum.GetEnumDescription();
            return DependencyProperty.UnsetValue;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
        public static EnumToDescriptionConverter Instance { get; } = new EnumToDescriptionConverter();
    }
}
using System;
using System.Windows.Markup;

namespace Core2022.SO.JosephWard
{
    [MarkupExtensionReturnType(typeof(EnumToDescriptionConverter))]
    public class EnumToDescriptionExtension : MarkupExtension
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return EnumToDescriptionConverter.Instance;
        }
    }
}
using System.ComponentModel;

namespace Core2022.SO.JosephWard
{
    public enum AllowedTag
    {
        [Description("Value not set")]
        None,
        [Description("First value")]
        First,
        [Description("Second value")]
        Second
    }
}
using System.Collections.ObjectModel;

namespace Core2022.SO.JosephWard
{
    public class EnumsViewModel
    {
        public ObservableCollection<AllowedTag> Tags { get; } = new ObservableCollection<AllowedTag>()
        { AllowedTag.None, AllowedTag.Second, AllowedTag.First };
    }
}
<Window x:Class="Core2022.SO.JosephWard.EnumsWindow"
        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:Core2022.SO.JosephWard"
        mc:Ignorable="d"
        Title="EnumsWindow" Height="150" Width="300">
    <Window.DataContext>
        <local:EnumsViewModel/>
    </Window.DataContext>
    <Grid>
        <ListBox ItemsSource="{Binding Tags}">
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="{x:Type local:AllowedTag}">
                    <TextBlock Text="{Binding Converter={local:EnumToDescription}}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 WPF SelectedValue的组合框不会从viewmodel属性更新 - WPF SelectedValue of combobox not updating from viewmodel property WPF组合框未更新ViewModel - WPF Combobox not updating ViewModel 当绑定列表更新时,WPF ListBox不会更新 - WPF ListBox not updating when Bound List is updated 更新绑定属性不会更新 WPF 中的视图 - Updating a Bound Property does not update the View in WPF WPF用户控件依赖项属性绑定到ViewModel属性时不起作用 - WPF User Control Dependency Property not working when bound to a ViewModel property WPF-属性更改时绑定控件未更新? - WPF - Bound Control Not Updating When Property Changed? 相应的CustomControl属性更新时,ViewModel属性未更新 - ViewModel property not updating when it's corresponding CustomControl property is updated WPF ItemsControl绑定在绑定到视图模型中的对象中的ObservableCollection时不会更新 - WPF ItemsControl binding not updating when bound to an ObservableCollection in an object in the View Model 绑定到WPF组合框的“ SelectedItem”的属性的奇怪行为 - Weird behavior for a property bound to the 'SelectedItem' of a WPF Combobox 当视图模型更新其绑定属性时,需要将插入符号移动到文本框的末尾 - Need to move caret to end of a textbox when its bound property is updated by the viewmodel
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM