0

我有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; }
    }
}
4

1 回答 1

0

问题是您只有一个按钮,这与列表视图的选定项无关。

你禁用它,一个按钮被禁用。

您需要将该状态与特定用户相关联,并将模板化按钮的状态绑定到该状态。

    <Window.Resources>
        <DataTemplate DataType="{x:Type local:User}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>

                <StackPanel>
                    <Button Name="BtnGetStatus"
                            Click="BtnGetStatus_Click"
                            Visibility="{Binding Visibility}"
                            IsEnabled="{Binding IsEnabled}"
                        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"
                    Content="{Binding ElementName=lv_data, Path=SelectedItem}">
        </ContentControl>
    </Grid>
</Window>

按钮绑定它的状态。

每个用户现在都有一个状态来呈现给它的模板按钮,并且与所选项目相关。

我已经实现了 inotifypropertychanged,因此当属性更改时,视图将获取新值。

    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 async void BtnGetStatus_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            User selectedUser = btn.DataContext as User;

            if (selectedUser==null)
            {
                return;
            }
            selectedUser.IsEnabled = false;
            selectedUser.Visibility = Visibility.Collapsed;

            await Task.Run(() => doStuffAsync(selectedUser));
            selectedUser.IsEnabled = true;
            selectedUser.Visibility = Visibility.Visible;
        }
        private async Task<bool> doStuffAsync(User user)
        {
            // Do something expensive
            await Task.Delay(10000);
            return true;
        }

    }

    public class User : INotifyPropertyChanged
    {
        public int UserID { get; set; }
        public string Username { get; set; }

        private bool isEnabled;

        public bool IsEnabled
        {
            get { return isEnabled; }
            set { isEnabled = value; RaisePropertyChanged(); }
        }
        private Visibility visibility;

        public Visibility Visibility
        {
            get { return visibility; }
            set { visibility = value; RaisePropertyChanged(); }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged([CallerMemberName] String propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

    }
于 2019-09-14T15:48:16.157 回答