【问题标题】:Control not visible even visibility set to visible即使可见性设置为可见,控件也不可见
【发布时间】:2018-02-16 12:17:48
【问题描述】:

我正在创建一个窗口,在该窗口中单击保存与数据库通信并将数据保存在数据库中。我想在单击保存时显示进度图像,直到数据未保存在数据库中。我已将图像的可见性设置为 true,但进度图像仍然不可见。

我已经完成了以下代码...

在 xml 文件中..

    <TextBox x:Name="txt_Comment" VerticalScrollBarVisibility="Auto"  TextWrapping="Wrap" AcceptsReturn="True" MaxLength="5000"  Margin="2,2,2,0"></TextBox>
    <WrapPanel Grid.Row="1" HorizontalAlignment="Center" Margin="10,-15,0,0" VerticalAlignment="Center">
        <Button x:Name="btn_Ok" Margin="0,0,0,0" HorizontalAlignment="Center"  VerticalAlignment="Center" Click="btn_Save_Click"  Height="25" Width="55">Save</Button>
        <Button x:Name="btn_Cancel" Margin="10,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center"  Height="25" Width="55" Content="Cancel" Click="btn_Cancel_Click" >
        </Button>
    </WrapPanel>

    <Grid Grid.RowSpan="2" Background="Black" Opacity="0.25" Name="LoadingAdorner" Visibility="Hidden"/>
    <Border Width="400" Grid.RowSpan="2"  Opacity="1" Height="180" Visibility="Hidden" HorizontalAlignment="Center" VerticalAlignment="Center" CornerRadius="2" x:Name="loaderBorder">
        <Border.Background>
            <LinearGradientBrush  EndPoint="1,1" StartPoint="0,0" >
                <GradientStop Color="#EBF6FA" Offset="0.3"/>
                <GradientStop Color="#b7d9e5" Offset="1.0"/>
            </LinearGradientBrush>
        </Border.Background>
        <Border.Effect>
            <DropShadowEffect BlurRadius="5" Color="#FFB0B0B0" ShadowDepth="3" />
        </Border.Effect>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="30"/>
                <RowDefinition/>
                <RowDefinition Height="95"/>
            </Grid.RowDefinitions>
            <Controls:LoadingAnimation Grid.Row="1" HorizontalAlignment="Center" FontWeight="Bold" LoadingText="Loading..."  VerticalAlignment="Center" />
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" FontFamily="Arial" Foreground="#647883" FontSize="14" Grid.Row="2" Text="Saving..."></TextBlock>
        </Grid>

    </Border>
</Grid>

在页面后面的代码中..

BackgroundWorker worker = new BackgroundWorker { WorkerSupportsCancellation = true };
worker.DoWork += delegate(object sender1, DoWorkEventArgs e1)
{
    CurrentDispatcher.Invoke(
        new Action(() =>
        {
            if (!string.IsNullOrEmpty(txt_Comment.Text))
            {
                LoadingAdorner.Visibility = Visibility.Visible;
                loaderBorder.Visibility = Visibility.Visible;
                using (Entities DB = new Entities(settings.LinqConnection))
                 {
                    if (txt_Comment.Text.Length > 1000)
                    {//In this case loading image is visible
                        MessageBox.Show("Comment is too large.", "Alert !", MessageBoxButton.OK, MessageBoxImage.Warning);
                        return;
                    }

                    var comment = DB.Table1.Create();//Here loading image is not visible.
                    comment.value = txt_Comment.Text;
                    comment.Date = DateTime.Now;
                    comment.ModifiedBy = settings.CurrentUID;
                    DB.Table1.Add(comment);

                    DB.SaveChanges();
                }
            }
        }),
    DispatcherPriority.Normal);
};

worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
    this.DialogResult = true;
    this.Close();
    LoadingAdorner.Visibility = Visibility.Collapsed;
    loaderBorder.Visibility = Visibility.Collapsed;
};

worker.RunWorkerAsync();

当消息框可见时,加载图像可见,但当数据保存在数据库中时,加载图像不可见。

【问题讨论】:

  • 我没有看到任何多线程在这里发生...您希望用户界面在数据库操作发生时如何响应?
  • 我也在代码中添加了线程部分..
  • 您的整个工作通过CurrentDispatcher.Invoke 路由回UI 线程。 “请在操作正在进行时冻结我的 UI” 是一种令人费解的说法
  • @Deepakgupta 你这是什么意思?
  • @rory.ap 当消息可见时,加载图像在窗口上可见,但在执行 db 操作时不可见..

标签: c# .net wpf entity-framework linq


【解决方案1】:

这就是我在这种情况下会做的事情:

创建委托以更新您的可见性和相应的方法

将您的匿名函数包装在与 doWork 事件兼容的函数中

当您需要更新可见性时,创建一个新的委托并使用 dispatcher.BeginInvoke() 调用更新方法。

    private delegate void UpdateVisibilityDelegate(Visibility visibility);

    private void UpdateVisiblity(Visibility visibility)
    {
        //LoadingAdorner.Visibility = visibility;
        //loaderBorder.Visibility = visibility;
    }

    private void Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        // Your Action() code here
        // Change the visibility using this method
        Dispatcher.CurrentDispatcher.BeginInvoke(new UpdateVisibilityDelegate(this.UpdateVisiblity), Visibility.Visible);

    }

【讨论】:

    【解决方案2】:

    将您的 using 块移出 CurrentDispatcher.Invoke() 并放在此调用之后。

    BackgroundWorker worker = new BackgroundWorker { WorkerSupportsCancellation = true };
            worker.DoWork += delegate(object sender1, DoWorkEventArgs e1)
            {
                CurrentDispatcher.Invoke(
                                     new Action(() =>
                                     {
                                         if (!string.IsNullOrEmpty(txt_Comment.Text))
                                         {
                                             LoadingAdorner.Visibility = Visibility.Visible;
                                             loaderBorder.Visibility = Visibility.Visible;                                         
                                         }
                                     }),
                                     DispatcherPriority.Normal);
    
                                     using (Entities DB = new Entities(settings.LinqConnection))
                                             {
                                                 if (txt_Comment.Text.Length > 1000)
                                                 {//In this case loading image is visible
    
                                                     MessageBox.Show("Comment is too large.", "Alert !", MessageBoxButton.OK, MessageBoxImage.Warning);
                                                     return;
                                                 }
    
                                                 var comment = DB.Table1.Create();//Here loading image is not visible.
                                                 comment.value = txt_Comment.Text;
                                                 comment.Date = DateTime.Now;
                                                 comment.ModifiedBy = settings.CurrentUID;
                                                 DB.Table1.Add(comment);
    
                                                 DB.SaveChanges();
                                             }
            };
    

    所以这段代码对我有用:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var worker = new BackgroundWorker { WorkerSupportsCancellation = true };
        worker.DoWork += delegate (object sender1, DoWorkEventArgs e1)
        {
            Dispatcher.Invoke(
                                 new Action(() =>{testCtl.Visibility = Visibility.Visible;}),
                                 System.Windows.Threading.DispatcherPriority.Normal);
            Task.Delay(3000).Wait();
        };
        worker.RunWorkerCompleted += delegate (object s, RunWorkerCompletedEventArgs args)
        {
            testCtl.Visibility = Visibility.Collapsed;
        };
        worker.RunWorkerAsync();
    }
    

    【讨论】:

    • @Deepakgupta 虽然它工作,但我看不到在后台任务开始执行时设置Visibility.Visible 的好处,而不是在用户单击按钮时立即设置它。 . 用户通常想知道他的输入已被接收并将被处理,而不是被告知技术细节(任务执行的确切开始时间)
    • 在 CurrentDispatcher.Invoke() 之外移动“使用”块对我有用。
    猜你喜欢
    • 2021-08-10
    • 2015-12-20
    • 1970-01-01
    • 1970-01-01
    • 2015-04-13
    • 1970-01-01
    • 2015-12-17
    • 2019-04-30
    • 1970-01-01
    相关资源
    最近更新 更多