我有一个NumericBox自定义控件,它具有StatusMessage依赖属性 -
public static readonly DependencyProperty StatusMessageProperty = DependencyProperty.Register("StatusMessage", typeof(string), typeof(EditBoxBase), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsRender, UiPropertyChanged));
public string StatusMessage
{
get => (string)GetValue(StatusMessageProperty);
set => SetValue(StatusMessageProperty, value);
}
NumericBox XAML:
<Grid x:Name="LayoutRoot" DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType={x:Type impinj:EditBoxBase}}}">
<controls:TextBox x:Name="InnerTextBox" TextChanged="TextBox_TextChanged" MaxLength="20" Text="{Binding Text, RelativeSource={RelativeSource AncestorType={x:Type impinj:EditBoxBase}}, UpdateSourceTrigger=PropertyChanged}">
</controls:TextBox>
和TextBox_TextChanged更新StatusMessage。
此控件在数据网格列外部和内部的MainWindow中使用,问题是数据网格列内的控件不会在文本更改时更新其状态消息,因为datagrid列外部的控件(后者是预期的行为)。
MainWindow XAML:
<Window.Resources>
<ResourceDictionary>
<viewModels:MainViewModelDesigner x:Key="MainViewModelDesigner" />
</ResourceDictionary>
</Window.Resources>
<Grid x:Name="LayoutRoot" d:DataContext="{Binding Source={StaticResource MainViewModelDesigner}}" UseLayoutRounding="True">
<Grid.RowDefinitions>
<RowDefinition x:Name="LotGridRow" Height="Auto"/>
<RowDefinition x:Name="ScrollableRegionHeaderRow" Height="Auto"/>
<RowDefinition x:Name="ScrollableRegionRow" Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="LotGrid" Grid.Row="0" Margin="30,10,0,10" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label x:Name="AngleBreakPrompt" Grid.Row="0" Grid.Column="0" Content="Angle Break: " HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
<controls:NumericBox x:Name="AngleBreakCount" Grid.Row="0" Grid.Column="1" Text="{Binding AngleBreakCount1, UpdateSourceTrigger=PropertyChanged}" TextChanged="EditBoxBase_TextChanged" ValidationErrorMessage="Angle Break Validation Message #1" StatusMessage="{Binding AngleBreakCountStatusMessage1, Mode=OneWayToSource}"/>
</Grid>
<ScrollViewer Grid.Row="1" x:Name="ScrollableRegion">
<ScrollViewer.Resources>
</ScrollViewer.Resources>
<Grid x:Name="ScrollableRegionGrid" d:DataContext="{Binding Source={StaticResource MainViewModelDesigner}}" UseLayoutRounding="True">
<Grid.RowDefinitions>
<RowDefinition x:Name="WaferHeaderRow" Height="Auto"/>
<RowDefinition x:Name="WaferGridRow" Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="1" Margin="30,15,30,15" BorderThickness="1" BorderBrush="DarkGray">
<DataGrid x:Name="WaferDataGrid" Margin="15,15,15,15" HorizontalAlignment="Left" VerticalAlignment="Center" ItemsSource="{Binding Wafers}" AutoGenerateColumns="False" FrozenColumnCount="1" HeadersVisibility="Column" Height="Auto" SelectionMode="Single" SelectionUnit="Cell" AlternatingRowBackground="#C4EBFF" CanUserReorderColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeColumns="False" CanUserResizeRows="False" CanUserSortColumns="False" VirtualizingStackPanel.IsVirtualizing="false">
<DataGrid.Columns>
<DataGridTemplateColumn Width="80" x:Name="AngleBreakColumn">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<controls:NumericBox x:Name="AngleBreakCount" Text="{Binding AngleBreakCount2, UpdateSourceTrigger=PropertyChanged}" TextChanged="EditBoxBase_TextChanged" ValidationErrorMessage="Angle Break Validation Message #2" StatusMessage="{Binding AngleBreakCountStatusMessage2, Mode=OneWayToSource}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Border>
</Grid>
</ScrollViewer>
</Grid>
来自MainViewModel,它是MainWindow的DataContext并实现了INotifyPropertyChanged -
private ObservableCollection<Wafer> _waferCollection = new ObservableCollection<Wafer>();
public ObservableCollection<Wafer> Wafers
{
get => _waferCollection;
set
{
_waferCollection = value;
OnPropertyChanged();
}
}
private string _angleBreakCount1;
public string AngleBreakCount1
{
get => _angleBreakCount1;
set
{
Debug.WriteLine($"{DateTime.Now:G}, In AngleBreakCount1 Setter");
if (_angleBreakCount1 == value)
return;
_angleBreakCount1 = value;
OnPropertyChanged();
}
}
private string _angleBreakCountStatusMessage1;
public string AngleBreakCountStatusMessage1
{
get => _angleBreakCountStatusMessage1;
set
{
Debug.WriteLine($"{DateTime.Now:G}, In AngleBreakCountStatusMessage1 Setter");
if (_angleBreakCountStatusMessage1 == value)
{
return;
}
_angleBreakCountStatusMessage1 = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
来自Wafer,它是datagrid的ItemsSource,也实现了INotifyPropertyChanged -
private string _angleBreakCount2;
public string AngleBreakCount2
{
get => _angleBreakCount2;
set
{
Debug.WriteLine($"{DateTime.Now:G}, In AngleBreakCount2 Setter");
if (_angleBreakCount2 == value)
{
return;
}
_angleBreakCount2 = value;
OnPropertyChanged();
}
}
private string _angleBreakCountStatusMessage2;
public string AngleBreakCountStatusMessage2
{
get => _angleBreakCountStatusMessage2;
set
{
Debug.WriteLine($"{DateTime.Now:G}, In Elusive AngleBreakCountStatusMessage2 Setter");
if (_angleBreakCountStatusMessage2 == value)
{
return;
}
_angleBreakCountStatusMessage2 = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
当datagrid列内的NumericBox中的文本因此更新了Wafer绑定到它的AngleBreakCount2时,绑定到其StatusMessage的Wafer上的AngleBreakCountStatusMessage2不会更新。当数据网格列外的NumericBox中的文本因此更新绑定到它的MainViewModel上的AngleBreakCount1时,绑定到其StatusMessage的MainViewModel上的AngleBreakCountStatusMessage1确实会更新,这是所需的行为。知道为什么datagrid列中的NumericBox没有显示所需的行为吗?