【问题标题】:VisualStateManager.GoToState not working on DataGrid within ChildWindowVisualStateManager.GoToState 在 ChildWindow 中的 DataGrid 上不起作用
【发布时间】:2015-10-22 11:48:07
【问题描述】:

我扩展了 System.Windows.Controls.DataGrid 控件,以便在 ItemsSource 为空或为空时添加静态空集合消息。判断消息是否显示的逻辑是使用视觉状态完成的,如下所示。此逻辑在页面或用户控件中完美运行,但是当我的扩展 DataGrid 直接在 ChildWindow 上使用时,即使触发逻辑没有错误,消息也不会出现。

扩展数据网格

    public class ReACTDataGrid : DataGrid
    {
        public bool IsFromChildWindow { get; set; }

        private IEnumerable _ItemsSource;
        public IEnumerable ItemsSource
        {
            get { return _ItemsSource; }
            set
            {
                _ItemsSource = value;
                base.ItemsSource = value;

                if (_ItemsSource.IsNullOrEmpty())
                    VisualStateManager.GoToState(this, "HasNoItems", false);
                else
                    VisualStateManager.GoToState(this, "HasItems", false);
            }
        }
    }

XAML 样式

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="data:DataGrid">
                <!--<Grid Background="{Binding Converter={StaticResource ThemeColorConverter}, ConverterParameter=Sub_Brush}" x:Name="Root">-->
                <Grid Background="White" x:Name="Root">
                    <vsm:VisualStateManager.VisualStateGroups>
                        <vsm:VisualStateGroup x:Name="EmptyMsg">
                            <vsm:VisualState x:Name="HasNoItems">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="EmptyCollectionMsg" Storyboard.TargetProperty="(UIElement.Visibility)">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </vsm:VisualState>
                            <vsm:VisualState x:Name="HasItems">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="EmptyCollectionMsg" Storyboard.TargetProperty="(UIElement.Visibility)">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </vsm:VisualState>
                        </vsm:VisualStateGroup>
                    </vsm:VisualStateManager.VisualStateGroups>
                    <Grid.Resources>
                        <ControlTemplate x:Key="TopLeftHeaderTemplate" TargetType="dataPrimitives:DataGridColumnHeader">
                            <Grid Margin="1">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="Auto" />
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="Auto" />
                                </Grid.ColumnDefinitions>
                                <Rectangle x:Name="Background" Opacity="0.65" Grid.ColumnSpan="3" Grid.RowSpan="3">
                                    <Rectangle.Fill>
                                        <LinearGradientBrush EndPoint="0.5,1.4" StartPoint="0.5,0">
                                            <GradientStop Color="{Binding Converter={StaticResource ThemeColorConverter}, ConverterParameter=Sub_Color}" Offset="0.75" />
                                            <GradientStop Color="{Binding Converter={StaticResource ThemeColorConverter}, ConverterParameter=Sub_Color}" Offset="1" />
                                        </LinearGradientBrush>
                                    </Rectangle.Fill>
                                </Rectangle>
                                <Border CornerRadius="10,10,40,40" x:Name="Highlight" RenderTransformOrigin="0.5,1" Grid.ColumnSpan="3">
                                    <Border.Background>
                                        <RadialGradientBrush>
                                            <RadialGradientBrush.RelativeTransform>
                                                <TransformGroup>
                                                    <ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.25" ScaleY="2" />
                                                    <TranslateTransform Y="-0.6" />
                                                </TransformGroup>
                                            </RadialGradientBrush.RelativeTransform>
                                            <GradientStop Color="#BFFFFFFF" Offset="0" />
                                            <GradientStop Color="#4CFFFFFF" Offset="1" />
                                        </RadialGradientBrush>
                                    </Border.Background>
                                </Border>
                            </Grid>
                        </ControlTemplate>
                        <ControlTemplate x:Key="TopRightHeaderTemplate" TargetType="dataPrimitives:DataGridColumnHeader">
                            <Grid Margin="1">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="Auto" />
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="Auto" />
                                </Grid.ColumnDefinitions>
                                <!-- Set opacity to zero to hide mess above scrollbar -->
                                <Rectangle x:Name="Background" Opacity="0" Grid.ColumnSpan="3" Grid.RowSpan="3">
                                    <Rectangle.Fill>
                                        <LinearGradientBrush EndPoint="0.5,1.4" StartPoint="0.5,0">
                                            <GradientStop Color="{Binding Converter={StaticResource ThemeColorConverter}, ConverterParameter=Main_Color}" Offset="0.75" />
                                            <GradientStop Color="{Binding Converter={StaticResource ThemeColorConverter}, ConverterParameter=Sub_Color}" Offset="1" />
                                        </LinearGradientBrush>
                                    </Rectangle.Fill>
                                </Rectangle>
                                <Border CornerRadius="0,0,40,40" x:Name="Highlight" Opacity="0" RenderTransformOrigin="0.5,1" Grid.ColumnSpan="3">
                                    <Border.Background>
                                        <RadialGradientBrush>
                                            <RadialGradientBrush.RelativeTransform>
                                                <TransformGroup>
                                                    <ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.25" ScaleY="2" />
                                                    <TranslateTransform Y="-0.6" />
                                                </TransformGroup>
                                            </RadialGradientBrush.RelativeTransform>
                                            <GradientStop Color="#BFFFFFFF" Offset="0" />
                                            <GradientStop Color="#4CFFFFFF" Offset="1" />
                                        </RadialGradientBrush>
                                    </Border.Background>
                                </Border>
                            </Grid>
                        </ControlTemplate>
                    </Grid.Resources>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <dataPrimitives:DataGridColumnHeader x:Name="TopLeftCornerHeader" Width="22" Template="{StaticResource TopLeftHeaderTemplate}" />
                    <dataPrimitives:DataGridColumnHeadersPresenter Grid.Column="1" x:Name="ColumnHeadersPresenter" />
                    <dataPrimitives:DataGridColumnHeader Grid.Column="2" x:Name="TopRightCornerHeader" Template="{StaticResource TopRightHeaderTemplate}" />
                    <Rectangle Grid.ColumnSpan="3" Height="1" x:Name="ColumnHeadersAndRowsSeparator" VerticalAlignment="Bottom" Width="Auto" Fill="#FFDBDCDC" StrokeThickness="1" />
                    <dataPrimitives:DataGridRowsPresenter Grid.ColumnSpan="2" Grid.Row="1" x:Name="RowsPresenter" />
                    <Rectangle Grid.Column="2" Grid.Row="2" x:Name="BottomRightCorner" Fill="{TemplateBinding Background}" />
                    <Rectangle Grid.ColumnSpan="2" Grid.Row="2" x:Name="BottomLeftCorner" Fill="{TemplateBinding Background}" />
                    <ScrollBar Grid.Column="2" Grid.Row="1" Margin="0" x:Name="VerticalScrollbar" Width="18" Orientation="Vertical" />
                    <Grid Grid.Column="1" Grid.Row="2">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Rectangle x:Name="FrozenColumnScrollBarSpacer" />
                        <ScrollBar Grid.Column="1" Height="18" Margin="0" x:Name="HorizontalScrollbar" Orientation="Horizontal" />
                    </Grid>
                    <TextBlock x:Name="EmptyCollectionMsg" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="2" Text="No Data Entered" Visibility="Collapsed"></TextBlock>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

【问题讨论】:

    标签: c# silverlight datagrid childwindow


    【解决方案1】:

    您可以尝试不在设置器中执行您的状态更改代码,而是在加载或卸载行时执行。因此,ItemsSource 中的任何更改最终都会触发您的代码。

    public class ReACTDataGrid : DataGrid
    {
        private bool templateApplied;
        protected override void OnApplyTemplate()
        {
            templateApplied = true;
            base.OnApplyTemplate();
            CheckIfItemsEmptyAndUpdateVisualState();
        }
    
        protected override void OnLoadingRow(DataGridRowEventArgs e)
        {
            if (templateApplied) CheckIfItemsEmptyAndUpdateVisualState();
        }
    
        protected override void OnUnloadingRow(DataGridRowEventArgs e)
        {
            if (templateApplied) CheckIfItemsEmptyAndUpdateVisualState();
        }
    
        private void CheckIfItemsEmptyAndUpdateVisualState()
        {
            if (this.ItemsSource.IsNullOrEmpty())
                VisualStateManager.GoToState(this, "HasNoItems", false);
            else
                VisualStateManager.GoToState(this, "HasItems", false);
        }
    }
    

    【讨论】:

      【解决方案2】:

      我怀疑观察到的行为不是由 ChildWindow 或 - 通常 - 在您的 UI 中的任何位置引起的。

      当我查看您对 ItemsSource 的重新定义时,我注意到您在那里放置了一些需要执行的代码,以触发 VisualState 更改(并更新基类属性以尝试保持本地值和 DependencyProperty 同步)。 但这不是DependencyProperties 的工作方式。 Bindings 不会调用 setter 或 getter,它们直接调用 SetValue(...) 和 GetValue(...) (MSDN)。因此,您使用的任何绑定都不会触发派生类中的设置器代码。

      我不会派生一个新类并提供整个ControlTemplate 的几乎重复,只是为了添加一个“这里没有项目”的标志。一个单纯的装饰。我宁愿用类似的东西来解决这个问题:

      <MyFancyView>
          ...
          <DataGrid ItemsSource="{...}">
              <Behaviors>
                  <ShowEmptySign/>
              <Behaviors>
          </DataGrid>
      
      </MyFancyView>
      

      和自定义行为

      public class ShowEmptySign : Behavior<ItemsControl>
      {
          private TextBlock msg;
          ...OnAttached()
          {
              var rootGrid=AssociatedObject.GetDecendant<Grid>();
              msg = new TextBlock(){...};
              rootGrid.Children.Add(msg)
              ((INotifyCollectionChanged)AssociatedObject.Items).CollectionChanged += CheckIfEmpty
              CheckIfEmpty();
          }
          ...CheckIfEmpty()
          {
              if(!AssociatedObject.Items.Any()) Show(); else Hide();
          }
          ...Show()
          {
              msg.Visibility = Visibility.Visible;
          }
      }
      

      我检查了 MSDN,发现 DataGrid 不是从 ItemsControl 派生的。因此,要实际使用它,必须将行为更改为使用 rowLoaded/rowUnloaded 事件而不是 collectionChanged 事件。

      【讨论】:

      • 感谢您的回复,但我的实现在页面和用户控件上的 Silverlight 应用程序中完美运行,而不是子窗口。我会看看你的建议,谢谢
      • 几年前继承的应用程序使用 ItemsSource 设置器,这不是我们扩展的 DataGrid 控件的唯一用途。我似乎找不到在全局样式资源字典中添加行为的方法(因为我们不想修改 DataGrid 控件的每个实例,因为有很多)&虽然我很欣赏你的意见,你的提问语气和当我只是寻求一些建议和帮助时,回复是彻头彻尾的粗鲁
      • 你是对的。我道歉。那不是我最光荣的时刻。
      • 我有一个想法,可以解决状态变化问题而不会造成太多麻烦。会把它写成一个新的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-11
      • 2016-01-16
      • 1970-01-01
      • 2013-06-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多