带有自定义控件的datagrid列内的WPF绑定问题

时间:2018-02-13 19:30:58

标签: wpf data-binding

我有一个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没有显示所需的行为吗?

0 个答案:

没有答案