【问题标题】:ComboBox SelectedItem not updatingComboBox SelectedItem 未更新
【发布时间】:2014-07-13 09:35:07
【问题描述】:

我正在使用 ComboBox (WPF 4.0) 为编辑器应用程序显示用户定义的段落样式。 ComboBox 有两列:

(1) 段落样式的无格式名称
(2) 文本“abcABC123”,部分属性根据第一列的段落样式格式化

这些是用户定义的段落样式类的公共属性(其中最后 3 个不是 ResourceKeys 而是包含 ResourceKeys 的变量):

_NameInternal
_NameUI
_ResourceKey_background
_ResourceKey_foreground
_ResourceKey_fontFamily

问题:ComboBox 显示一个 SelectedItem。如果我打开一个对话框,请更改 SelectedItem 的三个 Binding 属性中的一个或多个 (Background, Foreground, FontFamily) 并关闭对话框,然后 ComboBox 的 SelectedItem 不会更新。但如果我把它放下它会显示 新格式。

有没有办法在 Xaml 而不是 C# 中解决这个问题?

<Window.Resources>
    <local2:_2StylesPara x:Key="_2stylesPara" />
    <CollectionViewSource x:Key="_collectionViewSource_stylesPara" Source="{StaticResource _2stylesPara}">
        <CollectionViewSource.SortDescriptions>
            <!-- Requires 'xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"' declaration. -->
            <scm:SortDescription PropertyName="_NameUI" Direction="Ascending"/>
        </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
</Window.Resources>

<ComboBox Name="_cbStylesPara" HorizontalAlignment="Left" 
          ItemsSource="{Binding Source={StaticResource _collectionViewSource_stylesPara}}" 
          SelectedValuePath="_NameInternal" IsSynchronizedWithCurrentItem="True" >
    <ComboBox.Resources>
        <local2:_2ResourceLookupConverter x:Key="_resourceLookupConverter"/>
    </ComboBox.Resources>
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100"/>
                    <ColumnDefinition Width="100" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition />
                </Grid.RowDefinitions>
                <TextBlock Text="{Binding _NameUI}" Grid.Column="0" VerticalAlignment="Center" />
                <TextBlock Grid.Column="1" Text="abcABC123" Margin="3,0,0,0"
                           Background="{Binding _ResourceKey_background, Converter={StaticResource _resourceLookupConverter}}"
                           Foreground="{Binding _ResourceKey_foreground, Converter={StaticResource _resourceLookupConverter}}"
                           FontFamily="{Binding _ResourceKey_fontFamily, Converter={StaticResource _resourceLookupConverter}}"/>
            </Grid>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

后面的代码:

public class _2ResourceLookupConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return App.Current.TryFindResource(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

以下是用户定义的段落样式的 2 个类:

public class _2StylesPara : ObservableCollection<_2StylePara>
// ObservableCollection implements INotifyPropertyChanged
{
    public _2StylesPara(){}
}

public class _2StylePara
{
    public event PropertyChangedEventHandler PropertyChanged;

    // This method is not reached if Background, Foreground or FontFamily changes
    private void SetValue<T>(ref T property, T value, string propertyName = null)
    {
        if (object.Equals(property, value) == false)
        {
            property = value;

            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    private string _nameInternal = string.Empty;
    private string _nameUI = string.Empty;
    private string _resourceKey_background = string.Empty;
    private string _resourceKey_foreground = string.Empty;
    private string _resourceKey_fontFamily = string.Empty;
    private string _resourceKey_nameUI = string.Empty; 
    private string _resourceKey_style = string.Empty; 
    private Style _style = null;
    private ResourceDictionary _valuesRD = null;
    private string _pathToValuesRD = string.Empty;


    public string NameInternal
    {
        get { return this._nameInternal; }
        set { SetValue(ref this._nameInternal, value); }
    }

    public string NameUI
    {
        get { return this._nameUI; }
        set { SetValue(ref this._nameUI, value); }
    }

    public string ResourceKey_background
    {
        get { return this._resourceKey_background; }
        set { SetValue(ref this._resourceKey_background, value); }
    }

    public string ResourceKey_foreground
    {
        get { return this._resourceKey_foreground; }
        set { SetValue(ref this._resourceKey_foreground, value); }
    }

    public string ResourceKey_fontFamily
    {
        get { return this._resourceKey_fontFamily; }
        set { SetValue(ref this._resourceKey_fontFamily, value); }
    }

    public string ResourceKey_nameUI
    {
        get { return this._resourceKey_nameUI; }
        set { SetValue(ref this._resourceKey_nameUI, value); }
    }

    public string ResourceKey_style
    {
        get { return this._resourceKey_style; }
        set { SetValue(ref this._resourceKey_style, value); }
    }

    public Style Style
    {
        get { return this._style; }
        set { SetValue(ref this._style, value); }
    }

    public ResourceDictionary ValuesRD
    {
        get { return this._valuesRD; }
        set { SetValue(ref this._valuesRD, value); }
    }

    public string PathToValuesRD
    {
        get { return this._pathToValuesRD; }
        set { SetValue(ref this._pathToValuesRD, value); }
    }


    // Constructor
    public _2StylePara(Style sty, string styleNameInternal, string styleNameUI, string resourceKey_style, string resourceKey_nameUI,
                      string resourceKey_foreground, string resourceKey_background, string resourceKey_fontFamily,
                      ResourceDictionary valuesRD, string pathToValuesRD)
    {
        _style = sty;
        _nameInternal = styleNameInternal;                  // [ "_sty001" ]
        _nameUI = styleNameUI;                              // [ "Standard" ]

        _resourceKey_style = resourceKey_style;             // [ "_stylePara001" ]
        _resourceKey_nameUI = resourceKey_nameUI;           // [ "_nameUi001 ]
        _resourceKey_foreground = resourceKey_foreground;   // [ "_brush_textcolor001" ]
        _resourceKey_background = resourceKey_background;   // [ "_brush_backcolor001" ]
        _resourceKey_fontFamily = resourceKey_fontFamily;   // [ "_fontFamily001" ]

        _valuesRD = valuesRD;                               // This ResourceDictionary contains all style values
        _pathToValuesRD = pathToValuesRD;                   // [ "...\Resources\1ParaStyleValuesRD001.xaml" ]
    }
}

【问题讨论】:

  • 您是否在用户定义的段落样式类上实现了 INotifyPropertyChanged?

标签: c# xaml combobox updates selecteditem


【解决方案1】:

如果我理解正确,_ResourceKey_background 和其他属性是您的 _2sytlesPara 集合中包含的用户定义段落样式类的属性。您遇到的行为是,当您在后台更改这些属性时,视图不会更新。

在这种情况下,如果您更新模型(也称为 UDF 样式类实例之一),则应通知绑定有关更新。它由模型应触发的 INotifyPropertyChanged.PropertyChanged 事件完成。

绑定会自动以相反的方式工作,因此当您更改视图上的某些内容时,您的模型会更新。

通知的标准属性模式是:

class Model : INotifyPropertyChanged
{
    private int _Name = default(int);
    public int Name
    {
        get { return _Name; }
        set
        {
            SetValue(ref this._Name, value);
        }
    }

    private void SetValue<T>(ref T property, T value, [CallerMemberName]string propertyName = null)
    {
        if (object.Equals(property, value) == false)
        {
            property = value;

            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

我希望我能理解您的问题并能提供帮助。

更新:

IObservableCollection 仅通知绑定机制有关集合中的添加和删除。项的嵌套属性值的更改仍然不会自动反映。

关于您的代码,我建议尝试以下修改:

首先,我不建议使用下划线开头的公共属性名称。根据 MS 命名约定,以下划线开头的名称通常是私有的支持字段。

所以,改变相应的属性,如:

private string _ResourceKey_nameUI = string.Empty;
public string ResourceKey_nameUI
{
    get { return this._ResourceKey_nameUI; }
    set { SetValue(ref this._ResourceKey_nameUI, value); }
}

同时更改对属性的绑定:

<TextBlock Grid.Column="1" Text="abcABC123" Margin="3,0,0,0" 
Background="{Binding ResourceKey_background, Converter={StaticResource _resourceLookupConverter}}" 
Foreground="{Binding ResourceKey_foreground, Converter={StaticResource _resourceLookupConverter}}"
FontFamily="{Binding ResourceKey_fontFamily, Converter={StaticResource _resourceLookupConverter}}"/>

更新 2

WPF 绑定检查绑定的模型实例是否实现了 INotifyPropertyChanged 接口。 请将您的类声明修改为:

public class _2StylePara : INotifyPropertyChanged
{
//...
}

此外,当您在后台更改值时,您应该使用属性而不是支持字段。因此,当您更改 NameUI 时,将调用 SetValue 方法,它会通知绑定刷新 TextBlock。绑定还应该指向属性,而不是支持字段。

因此:Text="{Binding NameUI}" NOT Text="{Binding _NameUI}" 如果有帮助,请标记为答案。谢谢。

【讨论】:

  • 对不起,我注意到 ObservableCollection 实现了 INotifyPropertyChanged,已经更新了我的第一篇文章。
  • 尝试了你的最后一个建议,但不幸的是它没有任何区别,同样的结果。
  • 您可以在更改属性值的地方发布您的代码吗?
  • 根据您的更新 2 修改了类声明,现在可以使用了,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-28
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 2013-05-17
  • 1970-01-01
相关资源
最近更新 更多