【问题标题】:WPF ListView doesn't update on PropertyChangedWPF ListView 不会在 PropertyChanged 上更新
【发布时间】:2014-08-15 07:11:00
【问题描述】:

我有一个 WPF 列表视图,它在组合框中显示材质、厚度和厚度单位...xaml 看起来像这样(为了清晰起见,我删除了所有可视化设置):

    <ListView ItemsSource="{Binding Path=MaterialLayers}" IsSynchronizedWithCurrentItem="True">
        <ListView.Resources>
            <x:Array x:Key="DistanceUnitItems" Type="sys:String" xmlns:sys="clr-namespace:System;assembly=mscorlib">
                <sys:String>cm</sys:String>
                <sys:String>inches</sys:String>
            </x:Array>
            <DataTemplate x:Key="ThicknessUnit">
                <ComboBox ItemsSource="{StaticResource DistanceUnitItems}" SelectedIndex="{Binding ThicknessUnit}" />
            </DataTemplate>
        </ListView.Resources>
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Material Name" DisplayMemberBinding="{Binding MaterialName}"/>
                <GridViewColumn Header="Material Thickness" DisplayMemberBinding="{Binding MaterialThickness}"/>  />
                <GridViewColumn Header="Thickness Unit" CellTemplate="{StaticResource ThicknessUnit}"  />
            </GridView>
        </ListView.View>
    </ListView>

MaterialLayersObservableCollection&lt;MaterialLayer&gt;

MaterialLayer 具有 MaterialName、MaterialThickness 和 ThicknessUnit 的属性(0 表示厘米,1 表示英寸)。 MaterialThickness 将内部存储的值(以厘米为单位)转换为厚度单位指定的单位。

当ThicknessUnit 改变时,我的DataViewModel 调用PropertyChanged 事件处理程序,属性名称为“MaterialLayers”。

所以,我希望 MaterialThickness 在 ThicknessUnit 更改时自动更新。

我已经对其进行了调试,并且调用了 PropertyChanged("MaterialLayers")。(当调用 ThicknessUnit 设置方法时,它调用父数据类 (MyData) 上的一个事件,该事件调用 DataViewModel 上的一个事件,该事件调用PropertyChanged 处理程序。)

DataViewModel 中的相关代码

    public delegate void DataChangedHandler(String identifier);

    public DataViewModel()
    {
        Data = new MyData();
        Data.DataChanged += new DataChangedHandler(RaisePropertyChanged);
    }

    public ObservableCollection<XTRRAMaterialLayer> MaterialLayers
    {
        get { return _data.MaterialLayers; }
        set { }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propertyName)
    {
        // take a copy to prevent thread issues
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

MyData 中的相关代码

public class XTRRAData
{
    public ObservableCollection<XTRRAMaterialLayer> MaterialLayers { get; set; }

    public event DataChangedHandler DataChanged;



    public MyData()
    {
        MaterialLayers = new ObservableCollection<MaterialLayer>();
    }

    public void myDataChanged(String identifier)
    {
        DataChanged(identifier);
    }

    public void AddLayer()
    {
        MaterialLayer layer = new MaterialLayer() { MaterialName="Test", MaterialThickness=5, ThicknessUnit=0 };

        layer.DataChanged += new DataChangedHandler(myDataChanged); 
    }
}

MaterialLayer 的相关代码

public class XTRRAMaterialLayer
{
    public XTRRAMaterialLayer()
    {
        _thicknessUnit = 0; // cm
    }
    public event DataChangedHandler DataChanged;

    public String MaterialName { get; set; }

    public double MaterialThickness
    {
        get
        {
            switch (_thicknessUnit)
            {
                default:
                case 0:
                    return DIST;
                case 1:
                    return DIST * 0.393700787;
            }
        }
        set
        {
            switch (_thicknessUnit)
            {
                default:
                case 0:
                    DIST = value;
                    break;
                case 1:
                    DIST = value / 0.393700787;
                    break;
            }

        }
    }

    public int _thicknessUnit;

    public int ThicknessUnit
    {
        get { return(int) _thicknessUnit;  }
        set
        {
            _thicknessUnit = (eThicknessUnits)value;
            FireDataChanged("MaterialLayers");
        }
    }

    public void FireDataChanged(String identifier)
    {
        if(DataChanged!=null)
        {
            DataChanged(identifier);
        }
    }

}

谁能帮忙?

【问题讨论】:

  • 如果支持数据的实例与以前相同,WPF 将不会重新绑定 UI。您似乎正在为整个 ItemsSource 集合提高 PropertyChanged,这不会导致任何结果。顺便说一句,在与实际属性定义不同的类中提升 propertychanged 也不会导致任何结果。贴出 ViewModel 和数据项的相关代码。
  • @HighCore 我添加了请求的代码。从 ViewModel 调用 PropertyChanged。如何在子项上正确调用 propertychanged?我试过“MaterialThickness”,但没有用。

标签: c# wpf listview binding inotifypropertychanged


【解决方案1】:

您需要在要更改的属性所在的类中实现INotifyPropertyChanged - 在您的情况下为 XTRRAMaterialLayer,并在属性更改时引发 PropertyChanged 事件。

您的属性应如下所示:

public int ThicknessUnit
{
    get { return(int) _thicknessUnit;  }
    set
    {
        _thicknessUnit = (eThicknessUnits)value;
        NotifyPropertyChanged();
    }
}

NotifyPropertyChanged 事件处理程序:

public event PropertyChangedEventHandler PropertyChanged;

// This method is called by the Set accessor of each property. 
// The CallerMemberName attribute that is applied to the optional propertyName 
// parameter causes the property name of the caller to be substituted as an argument. 
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

【讨论】:

  • 感谢您的回复,解决了问题。我只是没有正确理解 PropertyChanged 需要从哪里来,但答案是有道理的。对上述内容的唯一更改是,在我的 ThicknessUnit 设置器中,我还需要调用 NotifyPropertyChanged("MaterialThickness") 以使该字段在列表视图中更新。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
  • 2011-07-29
  • 1970-01-01
  • 2013-04-25
  • 2016-07-29
  • 1970-01-01
  • 2014-01-26
相关资源
最近更新 更多