【问题标题】:How does a XAML attribute bind to a INotifyPropertyChanged objectXAML 属性如何绑定到 INotifyPropertyChanged 对象
【发布时间】:2013-04-15 14:06:49
【问题描述】:

有一个实现 INotifyPropertyChanged 接口的类,如下所示:

public class ColorNotify : INotifyPropertyChanged
{   
    public event PropertyChangedEventHandler PropertyChanged;

    private SolidColorBrush bindableColor;
    public SolidColorBrush BindableColor
    {
        get { return bindableColor; }
        set
        {
            bindableColor = value;
            OnPropertyChanged("BindableColor");
        }
    }  

    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));   
        } 
    } 
}

我的 MainPage.xaml.cs 中的一个字段是这样的:

private ColorNotify DisabledColor; 

但我也尝试将上述字段作为属性,而不是像这样:

private ColorNotify disabledColor;
public ColorNotify DisabledColor
{
    get
    { return disabledColor; }
    set
    { disabledColor = value; }
}

MainPage.xaml.cs 中还有这个方法:

private void Legend_Refreshed(object sender, Legend.RefreshedEventArgs Lgd_Refreshed_EvArgs)
{
    LayerItemViewModel layerItmViewMdl;
    ObservableCollection<LayerItemViewModel> layerItms;

    layerItmViewMdl = Lgd_Refreshed_EvArgs.LayerItem;
    Layer legendItemLyr = layerItmViewMdl.Layer; 

    if (!legendItemLyr.IsInitialized)
    { 
        DisabledColor = new ColorNotify();
        DisabledColor.BindableColor = new SolidColorBrush(Colors.Red);
    }
    ...
    ...
}

在 MainPage.xaml 我有这个:

<esri:Legend 
        Map="{Binding ElementName=theMap}"
        LayerIDs="..." 
        Refreshed="Legend_Refreshed">
               <esri:Legend.MapLayerTemplate>
                       <DataTemplate>
                              <StackPanel Orientation="Horizontal" Width="Auto">
                                        <CheckBox Content="{Binding Label}" 
                                            Width="Auto" 
                                            IsChecked="{Binding IsEnabled, Mode=TwoWay}"
                                IsEnabled="{Binding IsInScaleRange}" 
                                            Foreground="{Binding Source=DisabledColor, Path=BindableColor}">
                                        </CheckBox>
                                        <Slider Maximum="1"  
                                            Value="{Binding Layer.Opacity, Mode=TwoWay}" 
                                            Width="80" />
                              </StackPanel>
                       </DataTemplate>
...
...
...
</esri:Legend>

注意上面的 XAML 代码:

Foreground="{Binding Source=DisabledColor, Path=BindableColor}">

那没用。

然后我在 XAML 中尝试了这个:

Foreground="{Binding BindableColor}"

但这也没用 如何将 Foreground 绑定到 ColorNotify 类的 BindableColor 属性? 绑定到 INotifyPropertyChanged 对象时,XAML 绑定应该是什么样子? (不通过 MVVM)

【问题讨论】:

  • 将该字段设为属性并将DisabledColor.BindableColor 作为您的路径
  • 顺便说一句,我已经尝试查看此链接以寻找类似的问题,但在那里我没有看到解决方案。 stackoverflow.com/questions/1962149/…
  • NSGaga,你的意思是我应该把“ColorNotify DisabledColor”变成一个属性吗?绑定应该是:“{Binding Path=DisabledColor.Bindablecolor}”?
  • @NSGaga,我尝试了以下方法:'Foreground="{Binding Path=DisabledColor.Bindablecolor}',我将属性设置为:'private ColorNotify disabledColor; public ColorNotify DisabledColor { get { return disabledColor ; } set { disabledColor = value; } }' 但这不起作用。
  • 在set 上执行OnNotifyChanged(并正确实施)-看看其他人的建议-或让我知道

标签: c# silverlight xaml


【解决方案1】:

如果你改变/初始化

private ColorNotify DisabledColor; 

在 View/ViewModel 加载之后,您需要将此属性更改为 public 并在其上实现 INotifyPropertyChange,就像您在 ColorNotify 上所做的一样。

【讨论】:

  • 我没有使用 MVVM。我将 DisabledProperty 字段更改为 public,但它不起作用。
【解决方案2】:

编辑:根据下面的评论讨论,我认为您应该使用这样的Convert 方法创建IValueConverter:

return new SolidColorBrush((bool)value ? Colors.Black : Colors.Red);

假设您的 IValueConverter 类名为 InitializedColorConverter,在您添加为 xmlns local 的命名空间中。在 XAML 中像这样使用它:

<UserControl.Resources>
    <local:InitializedColorConverter x:Key="InitializedColorConverter" />
</UserControl.Resources>
...
Foreground="{Binding IsInitialized, Converter = {StaticResource InitializedColorConverter}}"

结束编辑。我将把剩下的留在这里,因为它可能对有类似问题的人有用:

您需要将MainPage 上的字段更改为公共属性:

public ColorNotify DisabledColor { get; private set; }

如果您希望在 DisabledColor 本身发生更改时更新绑定,请同时在 MainPage(和此属性)上实现 INotifyPropertyChanged。

获得正确值绑定的一种更简单的方法是以编程方式进行。为此,请在您的对象上放置一个 Loaded 处理程序:

<CheckBox Content="{Binding Label}" 
          Width="Auto" 
          IsChecked="{Binding IsEnabled, Mode=TwoWay}"
          IsEnabled="{Binding IsInScaleRange}" 
          Loaded="MyCheckBoxLoaded">

让你的处理程序做这样的事情:

private void MyCheckBoxLoaded(object sender, System.Windows.RoutedEventArgs e)
{
    var cb = (CheckBox)sender;
    cb.SetBinding(Control.ForegroundProperty,
new System.Windows.Data.Binding("DisabledColor.Bindablecolor") { Source = this });
}

它看起来令人费解的原因是Source 必须是您的MainPage,不幸的是,在 Silverlight 中,这并不像看起来那么容易。

如果您的DisabledColor 在页面生命周期内永远不会更改,您可以将其保留为私有字段(将其标记为readonly 以确保这是真的)并在处理程序中执行此操作:

cb.SetBinding(Control.ForegroundProperty,
new System.Windows.Data.Binding("Bindablecolor") { Source = this.DisabledColor });

【讨论】:

  • 我不能使用复选框 Loaded 事件。上面 XAML 中显示的“Legend”元素将创建许多 MapLayerElement 对象(每个地图层一个),这意味着会有许多复选框。如果我使用复选框 Loaded 事件,那么我无法确定哪个复选框是哪个 MapLayerElement 的一部分,以及哪个 MapLayerElement 引用了哪个地图层。
  • 第 2 部分,每次创建 MapLayerElement 时都会调用“Legend”元素的 Legend_Refreshed 方法。在该方法中,我可以使用 Lgd_Refreshed_EvArgs 获取对地图层的引用,以便确定地图层是否已初始化。然后,如果它没有被初始化,我改变复选框的颜色。
  • 如果让DisabledColor 的范围成为MainPage 的实例有意义,我看不出我的代码有什么问题。我刚刚注意到您在代码示例中实际创建和设置的DisabledColor 是Legend_Refreshed 中的一个局部变量。如果MainPage 的范围是有意义的,那么就使用它;如果您将其设置为带有INotifyPropertyChanged 的属性,那么Loaded 可能在Legend_Refreshed 之前发生并不重要。如果该范围没有意义,请指定什么范围(例如MapLayerElement 的实例?)。
  • 问题,如果我要绑定很多复选框,我可以在 MainPage 上实现 INotifyPropertyChanged 吗?
  • 是的,您可以让任意数量的事物收听一个PropertyChanged 事件。
猜你喜欢
  • 2015-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-31
相关资源
最近更新 更多