列中的WPF绑定不起作用
我有一个列表对象,如下所示:列中的WPF绑定不起作用,wpf,binding,Wpf,Binding,我有一个列表对象,如下所示: public class Device : ObjectBase { private int _DeviceNbr; public int DeviceNbr { get { return _DeviceNbr; } set { _DeviceNbr = value; } } private string _DeviceName; public string DeviceName
public class Device : ObjectBase
{
private int _DeviceNbr;
public int DeviceNbr
{
get { return _DeviceNbr; }
set { _DeviceNbr = value; }
}
private string _DeviceName;
public string DeviceName
{
get { return _DeviceName; }
set { _DeviceName = value; OnPropertyChanged(); }
}
private ObservableCollection<State> _DeviceStates;
public ObservableCollection<State> DeviceStates
{
get { return _DeviceStates; }
set { _DeviceStates = value; OnPropertyChanged(); }
}
}
public class State: ObjectBase
{
public int StateNbr { get; set; }
private string _stateType;
public string StateType
{
get { return _stateType; }
set { _stateType = value; }
}
private int _value;
public int Value
{
get { return _value; }
set { _value = value; OnPropertyChanged(); }
}
}
public class CustomGrid : DataGrid
{
public ObservableCollection<ColumnConfig> ColumnConfigs
{
get { return GetValue(ColumnConfigsProperty) as ObservableCollection<ColumnConfig>; }
set { SetValue(ColumnConfigsProperty, value); }
}
public static readonly DependencyProperty ColumnConfigsProperty =
DependencyProperty.Register("ColumnConfigs", typeof(ObservableCollection<ColumnConfig>), typeof(CustomGrid), new PropertyMetadata(new PropertyChangedCallback(OnColumnsChanged)));
static void OnColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var dataGrid = d as CustomGrid;
dataGrid.Columns.Clear();
dataGrid.Columns.Add(new DataGridTextColumn() { Header = "Nbr", Binding = new Binding("DeviceNbr") });
dataGrid.Columns.Add(new DataGridTextColumn() { Header = "Device", Binding = new Binding("DeviceName") });
foreach (var columnConfig in dataGrid.ColumnConfigs.Where(c => c.IsVisible))
{
var column = new DataGridTextColumn()
{
Header = columnConfig.ColumnHeader,
Binding = new Binding("DeviceStates")
{
ConverterParameter = columnConfig.ColumnName,
Converter = new DeviceStateConverter(),
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
Mode =BindingMode.TwoWay
}
};
dataGrid.Columns.Add(column);
}
}
}
public class DeviceStateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is ObservableCollection<State> DeviceStates && parameter != null)
{
var DeviceState = DeviceStates.FirstOrDefault(s => s.StateType == parameter.ToString());
if (DeviceState != null)
return DeviceState.Value;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class MainViewModel : ObjectBase
{
private ObservableCollection<Device> _Devices;
public ObservableCollection<Device> Devices
{
get { return _Devices; }
set { _Devices = value; OnPropertyChanged(); }
}
private ObservableCollection<ColumnConfig> _columnConfigs;
public ObservableCollection<ColumnConfig> ColumnConfigs
{
get { return _columnConfigs; }
set { _columnConfigs = value; OnPropertyChanged(); }
}
public MainViewModel()
{
Devices = new ObservableCollection<Device>();
_columnConfigs = new ObservableCollection<ColumnConfig>()
{
new ColumnConfig(){ ColumnHeader = "On", ColumnName = "On", ColumnWidth= 100, IsVisible= true},
new ColumnConfig(){ ColumnHeader = "Off", ColumnName = "Off", ColumnWidth= 100, IsVisible= true}
};
for ( int i = 0; i <= 100; i++)
{
_Devices.Add(new Device()
{
DeviceNbr = i,
DeviceName = "Device " + i.ToString(),
DeviceStates = new ObservableCollection<State>()
{
new State() { StateType = "On", Value= i},
new State() { StateType = "Off", Value= i+1}
}
});
}
OnPropertyChanged("ColumnConfigs");
OnPropertyChanged("Devices");
}
public void TestStateChange ()
{
Devices[2].DeviceName = "Device X";
Devices[2].DeviceStates[0].Value = 5;
// OnPropertyChanged("Devices");
}
}
<local:CustomGrid
AutoGenerateColumns="False"
ColumnConfigs="{Binding ColumnConfigs}"
ItemsSource="{Binding Devices, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" />
因此,我必须在州的“父”集合中提出PropertyChangedEvent。真奇怪。
我现在唯一能想到的是在State类中实现一个事件,并让父集合对象订阅它
有人有更好的主意吗?如果您的
状态
对象实现INotifyPropertyChanged(所有可绑定的数据对象都应该实现INotifyPropertyChanged),并且如果您的datagrid列直接绑定到状态对象(即通过包含索引的绑定路径),则您的UI将按预期更新
您可以从父
设备
对象订阅状态
属性更改事件,然后从那里重新通知,但这是一种冗长的方法,意味着您必须订阅包含状态
对象的ObservableCollection
的CollectionChanged事件,以便您可以在每个状态
对象上附加/取消附加PropertyChange事件(有时这是唯一的方法,但如果可以避免)。如果您的状态
对象实现了INotifyPropertyChanged(所有可绑定数据对象都应该实现),并且如果您的datagrid列直接绑定到状态对象(即通过包含索引的绑定路径),则您的UI将按预期更新
您可以从父
设备
对象订阅状态
属性更改事件,然后从那里重新通知,但这是一种冗长的方法,意味着您必须订阅包含状态
对象的ObservableCollection
的CollectionChanged事件,以便您可以在每个状态
对象上从PropertyChange事件附加/取消附加(有时这是唯一的方法,但如果可以,请避免).什么是ObjectBase
?它是否实现了INotifyPropertyChanged
?您还需要为您的DeviceName
列设置TwoWayBinding
。您好。谢谢您的回答。是的,ObjectBase只是INotifyPropertyChanged实现。调用TestStateChange方法时,DeviceName会发生变化。噢,这是正确的ems我跳过了该部分。您是否尝试在Converter方法中设置断点,并观察值更改时是否调用该方法?值更改时将不会调用Convert方法。我还注释掉ConverterParameter,但没有成功。@XAMlMAX我不知道如何实现此目的。具体取决于设备将有不同数量的列。什么是ObjectBase
?它是否实现了INotifyPropertyChanged
?您还需要为DeviceName
列设置TwoWayBinding
。您好。感谢您的回答。是的,ObjectBase只是INotifyPropertyChanged实现。DeviceName更改为en TestStateChange方法被调用。哦,我似乎跳过了这一部分。您是否尝试在转换器方法中设置断点,并观察值更改时是否调用该方法?值更改时将不会调用Convert方法。我还注释了ConverterParameter,但没有成功。@XAMlMAX我不知道如何操作为了实现这一点。根据设备的类型,将有不同数量的列。“如果您的状态对象实现INotifyPropertyChanged(所有可绑定数据对象都应实现INotifyPropertyChanged),并且如果您的datagrid列直接绑定到状态对象(即通过包含索引的绑定路径),则您的UI将按预期更新。”您能告诉我如何在我的情况下做到这一点吗?“如果您的状态对象实现INotifyPropertyChanged(所有可绑定的数据对象都应该实现INotifyPropertyChanged),并且如果您的datagrid列直接绑定到状态对象(即通过包含索引的绑定路径),则您的UI将按预期更新。”你能告诉我如何在我的情况下做到这一点吗?
public void TestStateChange()
{
foreach (var device in Devices)
{
foreach (var state in device.DeviceStates)
{
state.Value = state.Value + 1;
}
device.OnPropertyChanged("DeviceStates");
}
}