WPF 数据绑定,属性值更改 UI 不刷新其内容
WPF data binding, on properties values changed the UI don't refresh its content
我知道有很多问题看起来像这样,但我在这里和其他论坛上都找不到任何人回答我的问题。
所以,我对 WPF 比较陌生,我正在测试数据绑定,但我遇到了一个问题,即当 ObservableCollection 的值发生变化时,数据没有更新值。
我会举我的例子。
Main.xaml
<Window x:Class="TestWPF.MainWindow"
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:TestWPF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid x:Name="MyGrid">
</Grid>
</Window>
Main.xaml.cs
using System.Windows;
namespace TestWPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Stand stand = new Stand("Best Seller Stand");
stand.cars.Add(new Car()
{
ID = "1",
Brand = "BMW",
CarNumber = 165,
HaveRadio = true
});
stand.cars.Add(new Car()
{
ID = "2",
Brand = "Toyota",
CarNumber = 421,
HaveRadio = true
});
stand.cars.Add(new Car()
{
ID = "4",
Brand = "FIAT",
CarNumber = 312,
HaveRadio = false
});
stand.cars.Add(new Car()
{
ID = "3",
Brand = "Ferrari",
CarNumber = 12,
HaveRadio = true
});
MyGrid.Children.Add(stand.GetCatalog());
}
}
}
Car.cs
using System;
namespace TestWPF
{
public class Car : IComparable, IComparable<int>
{
public string ID { get; set; }
public string Brand { get; set; }
public int CarNumber { get; set; }
public bool HaveRadio { get; set; }
public void GerateRandomCarNumber()
{
CarNumber = new Random().Next(int.MinValue, int.MaxValue);
}
public int CompareTo(int other)
{
return CarNumber.CompareTo(other);
}
public int CompareTo(object obj)
{
Car other = null;
if (obj is Car)
other = obj as Car;
return CarNumber.CompareTo(other.CarNumber);
}
}
}
Stand.cs
using System.Collections.Generic;
using System.Linq;
namespace TestWPF
{
public class Stand
{
public Stand(string name)
{
Name = name;
}
public string Name { get; set; }
public SortedSet<Car> cars { get; set; } = new SortedSet<Car>();
public Car BestChoice
{
get
{
return cars.First();
}
}
public StandCatalog Catalog { get; set; } = null;
public StandCatalog GetCatalog()
{
if (Catalog == null)
Catalog = new StandCatalog(this);
return Catalog;
}
}
}
StandCatalog.xaml(用户控件)
<UserControl x:Class="TestWPF.StandCatalog"
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:TestWPF"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel Orientation="Vertical">
<Label Name="StandName" Content="{Binding Model.Name}" Margin="10"/>
<Label Name="CarBrand" Content="{Binding Model.BestChoice.Brand}" Margin="10"/>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding CatalogCar}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}"/>
<DataGridTextColumn Header="Brand" Binding="{Binding Brand}"/>
<DataGridTextColumn Header="Car Number" Binding="{Binding CarNumber}"/>
<DataGridCheckBoxColumn Header="Have Radio" Binding="{Binding HaveRadio}"/>
</DataGrid.Columns>
</DataGrid>
<Button Content="Gerate Random Number" Click="btn_GerateRandomNumber"/>
</StackPanel>
</UserControl>
StandCatalog.xaml.cs
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace TestWPF
{
/// <summary>
/// Interaction logic for StandCatalog.xaml
/// </summary>
public partial class StandCatalog : UserControl
{
public Stand Model { get; init; }
public ObservableCollection<Car> CatalogCar { get; set; }
public StandCatalog()
{
InitializeComponent();
this.DataContext = this;
}
public StandCatalog(Stand model) : this()
{
Model = model;
CatalogCar = new ObservableCollection<Car>(Model.cars);
}
private void btn_GerateRandomNumber(object sender, RoutedEventArgs e)
{
foreach (var item in Model.cars)
{
item.GerateRandomCarNumber();
}
}
}
}
所以我得到了这个应用程序:
但是当我点击按钮生成随机数时,数据网格没有刷新,标签 (Name="CarBrand") 也没有改变...
当元素更改其值时,数据绑定不会刷新 UI 吗?
我知道值发生了变化,因为当我重新排序数据网格时,我得到了这个:
谁能帮帮我?
另一个问题,我正在使用 class Stand 作为 StandCatalog (view/controller) 的模型,同时使用 SortedSet 和 ObservableCollection 的最佳方式是什么?或者我应该在模型中使用 SortedSet 吗?
选项 1:INotifyPropertyChanged
Car
class 应实现 INotifyPropertyChanged
接口以在 属性 更改时通知目标。
public class Car : IComparable, IComparable<int>, INotifyPropertyChanged
{
private int _carNumber;
public string ID { get; set; }
public string Brand { get; set; }
public int CarNumber
{
get => _carNumber;
set
{
if (_carNumber == value) return;
_carNumber = value;
OnPropertyChanged();
}
}
public bool HaveRadio { get; set; }
public void GerateRandomCarNumber() { CarNumber = new Random().Next(int.MinValue, int.MaxValue); }
public int CompareTo(int other) { return CarNumber.CompareTo(other); }
public int CompareTo(object obj)
{
Car other = null;
if (obj is Car)
other = obj as Car;
return CarNumber.CompareTo(other.CarNumber);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
}
选项 2:DependencyProperty
将 CarNumber
属性 定义为 DependencyProperty
。基础架构将处理更改。
public class Car : DependencyObject, IComparable, IComparable<int>
{
public static readonly DependencyProperty
CarNumberProperty = DependencyProperty.Register("CarNumber", typeof(int), typeof(Car));
public string ID { get; set; }
public string Brand { get; set; }
public int CarNumber
{
get => (int)GetValue(CarNumberProperty);
set => SetValue(CarNumberProperty, value);
}
public bool HaveRadio { get; set; }
public void GerateRandomCarNumber() { CarNumber = new Random().Next(int.MinValue, int.MaxValue); }
public int CompareTo(int other) { return CarNumber.CompareTo(other); }
public int CompareTo(object obj)
{
Car other = null;
if (obj is Car)
other = obj as Car;
return CarNumber.CompareTo(other.CarNumber);
}
}
我知道有很多问题看起来像这样,但我在这里和其他论坛上都找不到任何人回答我的问题。
所以,我对 WPF 比较陌生,我正在测试数据绑定,但我遇到了一个问题,即当 ObservableCollection 的值发生变化时,数据没有更新值。
我会举我的例子。
Main.xaml
<Window x:Class="TestWPF.MainWindow"
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:TestWPF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid x:Name="MyGrid">
</Grid>
</Window>
Main.xaml.cs
using System.Windows;
namespace TestWPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Stand stand = new Stand("Best Seller Stand");
stand.cars.Add(new Car()
{
ID = "1",
Brand = "BMW",
CarNumber = 165,
HaveRadio = true
});
stand.cars.Add(new Car()
{
ID = "2",
Brand = "Toyota",
CarNumber = 421,
HaveRadio = true
});
stand.cars.Add(new Car()
{
ID = "4",
Brand = "FIAT",
CarNumber = 312,
HaveRadio = false
});
stand.cars.Add(new Car()
{
ID = "3",
Brand = "Ferrari",
CarNumber = 12,
HaveRadio = true
});
MyGrid.Children.Add(stand.GetCatalog());
}
}
}
Car.cs
using System;
namespace TestWPF
{
public class Car : IComparable, IComparable<int>
{
public string ID { get; set; }
public string Brand { get; set; }
public int CarNumber { get; set; }
public bool HaveRadio { get; set; }
public void GerateRandomCarNumber()
{
CarNumber = new Random().Next(int.MinValue, int.MaxValue);
}
public int CompareTo(int other)
{
return CarNumber.CompareTo(other);
}
public int CompareTo(object obj)
{
Car other = null;
if (obj is Car)
other = obj as Car;
return CarNumber.CompareTo(other.CarNumber);
}
}
}
Stand.cs
using System.Collections.Generic;
using System.Linq;
namespace TestWPF
{
public class Stand
{
public Stand(string name)
{
Name = name;
}
public string Name { get; set; }
public SortedSet<Car> cars { get; set; } = new SortedSet<Car>();
public Car BestChoice
{
get
{
return cars.First();
}
}
public StandCatalog Catalog { get; set; } = null;
public StandCatalog GetCatalog()
{
if (Catalog == null)
Catalog = new StandCatalog(this);
return Catalog;
}
}
}
StandCatalog.xaml(用户控件)
<UserControl x:Class="TestWPF.StandCatalog"
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:TestWPF"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel Orientation="Vertical">
<Label Name="StandName" Content="{Binding Model.Name}" Margin="10"/>
<Label Name="CarBrand" Content="{Binding Model.BestChoice.Brand}" Margin="10"/>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding CatalogCar}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}"/>
<DataGridTextColumn Header="Brand" Binding="{Binding Brand}"/>
<DataGridTextColumn Header="Car Number" Binding="{Binding CarNumber}"/>
<DataGridCheckBoxColumn Header="Have Radio" Binding="{Binding HaveRadio}"/>
</DataGrid.Columns>
</DataGrid>
<Button Content="Gerate Random Number" Click="btn_GerateRandomNumber"/>
</StackPanel>
</UserControl>
StandCatalog.xaml.cs
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace TestWPF
{
/// <summary>
/// Interaction logic for StandCatalog.xaml
/// </summary>
public partial class StandCatalog : UserControl
{
public Stand Model { get; init; }
public ObservableCollection<Car> CatalogCar { get; set; }
public StandCatalog()
{
InitializeComponent();
this.DataContext = this;
}
public StandCatalog(Stand model) : this()
{
Model = model;
CatalogCar = new ObservableCollection<Car>(Model.cars);
}
private void btn_GerateRandomNumber(object sender, RoutedEventArgs e)
{
foreach (var item in Model.cars)
{
item.GerateRandomCarNumber();
}
}
}
}
所以我得到了这个应用程序:
但是当我点击按钮生成随机数时,数据网格没有刷新,标签 (Name="CarBrand") 也没有改变... 当元素更改其值时,数据绑定不会刷新 UI 吗?
我知道值发生了变化,因为当我重新排序数据网格时,我得到了这个:
谁能帮帮我?
另一个问题,我正在使用 class Stand 作为 StandCatalog (view/controller) 的模型,同时使用 SortedSet 和 ObservableCollection 的最佳方式是什么?或者我应该在模型中使用 SortedSet 吗?
选项 1:INotifyPropertyChanged
Car
class 应实现 INotifyPropertyChanged
接口以在 属性 更改时通知目标。
public class Car : IComparable, IComparable<int>, INotifyPropertyChanged
{
private int _carNumber;
public string ID { get; set; }
public string Brand { get; set; }
public int CarNumber
{
get => _carNumber;
set
{
if (_carNumber == value) return;
_carNumber = value;
OnPropertyChanged();
}
}
public bool HaveRadio { get; set; }
public void GerateRandomCarNumber() { CarNumber = new Random().Next(int.MinValue, int.MaxValue); }
public int CompareTo(int other) { return CarNumber.CompareTo(other); }
public int CompareTo(object obj)
{
Car other = null;
if (obj is Car)
other = obj as Car;
return CarNumber.CompareTo(other.CarNumber);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
}
选项 2:DependencyProperty
将 CarNumber
属性 定义为 DependencyProperty
。基础架构将处理更改。
public class Car : DependencyObject, IComparable, IComparable<int>
{
public static readonly DependencyProperty
CarNumberProperty = DependencyProperty.Register("CarNumber", typeof(int), typeof(Car));
public string ID { get; set; }
public string Brand { get; set; }
public int CarNumber
{
get => (int)GetValue(CarNumberProperty);
set => SetValue(CarNumberProperty, value);
}
public bool HaveRadio { get; set; }
public void GerateRandomCarNumber() { CarNumber = new Random().Next(int.MinValue, int.MaxValue); }
public int CompareTo(int other) { return CarNumber.CompareTo(other); }
public int CompareTo(object obj)
{
Car other = null;
if (obj is Car)
other = obj as Car;
return CarNumber.CompareTo(other.CarNumber);
}
}