【发布时间】:2020-01-15 18:11:41
【问题描述】:
我有一个ListView 有一些行。您可以在列表中选择一个项目,然后您将获得详细视图(主详细信息视图)。
在详细信息视图中,我有一个按钮。当您单击一个按钮时,它会禁用它并执行一些昂贵的操作。
问题是由于某种原因,所有行的所有按钮都被禁用? 我在这里遗漏了什么吗?
private void BtnGetStatus_Click(object sender, RoutedEventArgs e) {
Button btn = sender as Button;
if (btn.DataContext is ListCollectionView view) {
if (view.CurrentItem is MyViewModel viewModel) {
// Strange - Disables all buttons not currently clicked
btn.IsEnabled = false;
BackgroundWorker _worker = new BackgroundWorker() { WorkerReportsProgress = false };
_worker.DoWork += (se, ev) => {
// Simulate Expensive operation
System.Threading.Thread.Sleep(10000);
};
_worker.RunWorkerCompleted += (se, ev) => {
// Strange - enables all buttons not just clicked
btn.IsEnabled = true;
};
_worker.RunWorkerAsync();
}
}
}
这是一个演示问题的简单示例。 如果您单击一个按钮并转到其他行按钮将折叠。
只有被点击的应该是
XAML
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Key="detailsUserTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel>
<Button Name="BtnGetStatus" Click="BtnGetStatus_Click"
Content="Click to start Expensive Operation">
</Button>
</StackPanel>
</Grid>
</DataTemplate>
<CollectionViewSource
Source="{Binding Source={x:Static local:MainWindow.Users}}"
x:Key="dataViewSource" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListView Name="lv_data"
ItemsSource="{Binding Source={StaticResource dataViewSource}}"
SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding Path=UserID}"/>
<GridViewColumn Header="Username" DisplayMemberBinding="{Binding Path=Username}"/>
<GridViewColumn Header="Is Enabled" DisplayMemberBinding="{Binding Path=IsEnabled}"/>
</GridView>
</ListView.View>
</ListView>
<ContentControl Grid.Column="1"
Width="Auto"
ContentTemplate="{StaticResource detailsUserTemplate}"
Content="{Binding Source={StaticResource dataViewSource}}">
</ContentControl>
</Grid>
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public static ObservableCollection<User> Users
{
get
{
return new ObservableCollection<User>
{
new User {UserID = 1, Username = "user 1", IsEnabled = true},
new User {UserID = 2, Username = "User 2", IsEnabled =true},
new User {UserID = 3, Username = "Username 3", IsEnabled = true},
new User {UserID = 4, Username = "Username 4", IsEnabled = false}
};
}
}
private void BtnGetStatus_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
btn.IsEnabled = false;
btn.Visibility = Visibility.Collapsed;
BackgroundWorker worker = new BackgroundWorker()
{
WorkerReportsProgress = false
};
worker.DoWork += (se, ev) =>
{
// Simulate expensive
System.Threading.Thread.Sleep(10000);
};
worker.RunWorkerCompleted += (se, ev) =>
{
btn.IsEnabled = true;
btn.Visibility = Visibility.Visible;
};
worker.RunWorkerAsync();
}
}
public class User
{
public int UserID { get; set; }
public string Username { get; set; }
public bool IsEnabled { get; set; }
}
}
【问题讨论】:
-
似乎您的第二个事件处理程序没有被考虑在内......我会寻求它
-
你应该看看 MVVM。使该命令从您用于每一行的视图模型中公开。然后,您可以使用 canexecute 来禁用命令并知道单击了哪个按钮。还要查看异步等待并在后台线程中运行任务,等待结果然后切换回启用的标志。
-
@Andy 我没有提到我正在使用 .net 4.0。 MVVM 在这里没有任何区别。问题是一旦调用 btn.IsEnabled,每个按钮都会被禁用。一旦完成昂贵的操作并且 btn.IsEnabled = true 所有按钮都会再次启用。这是为什么 ?谢谢
-
您没有提供您的问题的最小复制,所以任何人都可以做的就是猜测。 Click 是一个冒泡的路由事件。我猜你正在某个地方处理它,所有事件都会冒泡。您可能可以在列表视图级别处理它并使用 e.originalsource 作为按钮。 Mvvm 会有所作为,因为触发的 icommand 将位于用户单击按钮的特定行的数据上下文中。
-
@Andy 我添加了一个工作示例来演示该问题。