C# WPF Listview 项目刷新在 OnPropertyChanged 后不触发
C# WPF Listview item refresh not firing after OnPropertyChanged
我创建了一个视图控件来以图形方式显示数据。由于可能有多个视图实例,我使用了一个 ListView 控件并将其绑定到一个可观察的对象集合 - Sheets。 Sheets 是具有 sheet 和名称的 SheetContainer 对象的可观察集合。查看器显示 sheet.
列表视图的 xaml 看起来像:
<ListView x:Name="ListViewSheetSlider" Height="170" Grid.Row="1" BorderThickness="0"
ItemsSource="{Binding Sheets}" SelectionChanged="ListViewSheetSlider_SelectionChanged" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}" />
<Viewbox Width="150" Height="150">
<SheetViewer:Viewer SetSheet="{Binding MySheet, NotifyOnSourceUpdated=True}" />
</Viewbox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
SelectionChanged 方法如下所示:
private void UpdateSheetAndSlider()
{
workspace.Sheets[SelectedSheetIndex] = MySheetDesigner.Sheet;
// ((SheetContainer)ListViewSheetSlider.SelectedItem).MySheet = MySheetDesigner.Sheet;
Sheets[SelectedSheetIndex].MySheet = MySheetDesigner.Sheet;
}
private void MySheetDesigner_SheetChanged(object sender, EventArgs e)
{
UpdateSheetAndSlider();
}
private void ListViewSheetSlider_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int index = ListViewSheetSlider.SelectedIndex;
UpdateSheetAndSlider();
SelectedSheetIndex = index;
MySheetDesigner.Sheet = workspace.Sheets[index];
ListViewSheetSlider.UpdateLayout();
}
SheetContainer 的实现很简单。看起来像:
public class SheetContainer : INotifyPropertyChanged
{
public string Name { get; set; }
private Sheet mySheet;
public Sheet MySheet
{
get => mySheet;
set
{
mySheet = value;
OnPropertyChanged("MySheet");
}
}
#region INotifyPropertyChanged Handler
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
查看器 xaml 和代码隐藏看起来像:
<UserControl x:Class="SheetViewer.Viewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SheetViewer"
xmlns:cad="clr-namespace:Cad;assembly=Cad"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<cad:Cad
x:Name="CadSurface" >
</cad:Cad>
</Grid>
</UserControl>
隐藏代码:
public partial class Viewer : UserControl
{
public static readonly DependencyProperty SetSheetProperty =
DependencyProperty.Register("SetSheet", typeof(Sheet), typeof(Viewer), new
PropertyMetadata(default(Sheet), new PropertyChangedCallback(OnSetSheetChanged)));
public Sheet SetSheet
{
get { return (Sheet)GetValue(SetSheetProperty); }
set { SetValue(SetSheetProperty, value);}
}
private static void OnSetSheetChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
Viewer UserControl1Control = d as Viewer;
UserControl1Control.OnSetSheetChanged(e);
}
private void OnSetSheetChanged(DependencyPropertyChangedEventArgs e)
{
//tbTest.Text = e.NewValue.ToString();
Sheet s = (Sheet)e.NewValue;
DrawSheet(s);
}
public Viewer()
{
InitializeComponent();
}
private void DrawSheet(Sheet sheet)
{
CadSurface.Draw();
}
}
我希望 DrawSheet 方法在列表视图中的选择更改时触发。 属性 更改确实在 SheetContainer 中触发,但不会进一步传播以绘制 sheet。请注意,当填充列表视图时,会正确调用方法并绘制初始视图。
我花了很多时间,但不知何故遗漏了关键要素。有人可以帮忙吗?
谢谢
当分配给 SetSheet 的实例相同时,将不会触发 DependencyPropertyChanged 事件。这可以解释一切。重点是 DependencyProperty 在设置值之前检查旧值和新值是否相等。如果它们相等,则不会传播任何更改。
我创建了一个视图控件来以图形方式显示数据。由于可能有多个视图实例,我使用了一个 ListView 控件并将其绑定到一个可观察的对象集合 - Sheets。 Sheets 是具有 sheet 和名称的 SheetContainer 对象的可观察集合。查看器显示 sheet.
列表视图的 xaml 看起来像:
<ListView x:Name="ListViewSheetSlider" Height="170" Grid.Row="1" BorderThickness="0"
ItemsSource="{Binding Sheets}" SelectionChanged="ListViewSheetSlider_SelectionChanged" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}" />
<Viewbox Width="150" Height="150">
<SheetViewer:Viewer SetSheet="{Binding MySheet, NotifyOnSourceUpdated=True}" />
</Viewbox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
SelectionChanged 方法如下所示:
private void UpdateSheetAndSlider()
{
workspace.Sheets[SelectedSheetIndex] = MySheetDesigner.Sheet;
// ((SheetContainer)ListViewSheetSlider.SelectedItem).MySheet = MySheetDesigner.Sheet;
Sheets[SelectedSheetIndex].MySheet = MySheetDesigner.Sheet;
}
private void MySheetDesigner_SheetChanged(object sender, EventArgs e)
{
UpdateSheetAndSlider();
}
private void ListViewSheetSlider_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int index = ListViewSheetSlider.SelectedIndex;
UpdateSheetAndSlider();
SelectedSheetIndex = index;
MySheetDesigner.Sheet = workspace.Sheets[index];
ListViewSheetSlider.UpdateLayout();
}
SheetContainer 的实现很简单。看起来像:
public class SheetContainer : INotifyPropertyChanged
{
public string Name { get; set; }
private Sheet mySheet;
public Sheet MySheet
{
get => mySheet;
set
{
mySheet = value;
OnPropertyChanged("MySheet");
}
}
#region INotifyPropertyChanged Handler
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
查看器 xaml 和代码隐藏看起来像:
<UserControl x:Class="SheetViewer.Viewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SheetViewer"
xmlns:cad="clr-namespace:Cad;assembly=Cad"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<cad:Cad
x:Name="CadSurface" >
</cad:Cad>
</Grid>
</UserControl>
隐藏代码:
public partial class Viewer : UserControl
{
public static readonly DependencyProperty SetSheetProperty =
DependencyProperty.Register("SetSheet", typeof(Sheet), typeof(Viewer), new
PropertyMetadata(default(Sheet), new PropertyChangedCallback(OnSetSheetChanged)));
public Sheet SetSheet
{
get { return (Sheet)GetValue(SetSheetProperty); }
set { SetValue(SetSheetProperty, value);}
}
private static void OnSetSheetChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
Viewer UserControl1Control = d as Viewer;
UserControl1Control.OnSetSheetChanged(e);
}
private void OnSetSheetChanged(DependencyPropertyChangedEventArgs e)
{
//tbTest.Text = e.NewValue.ToString();
Sheet s = (Sheet)e.NewValue;
DrawSheet(s);
}
public Viewer()
{
InitializeComponent();
}
private void DrawSheet(Sheet sheet)
{
CadSurface.Draw();
}
}
我希望 DrawSheet 方法在列表视图中的选择更改时触发。 属性 更改确实在 SheetContainer 中触发,但不会进一步传播以绘制 sheet。请注意,当填充列表视图时,会正确调用方法并绘制初始视图。
我花了很多时间,但不知何故遗漏了关键要素。有人可以帮忙吗?
谢谢
当分配给 SetSheet 的实例相同时,将不会触发 DependencyPropertyChanged 事件。这可以解释一切。重点是 DependencyProperty 在设置值之前检查旧值和新值是否相等。如果它们相等,则不会传播任何更改。