SignalR应用中DataGrid单元格按钮点击后切换状态与事件的问题
问题描述
开发SignalR应用时,DataGrid单元格内的ToggleButton点击后可切换内容,但绑定Checked/Unchecked事件时出现异常:要么仅单个事件生效,要么点击后按钮立刻恢复默认状态,无法正常触发对应事件并保持切换后的状态。
尝试的XAML方案1
<DataGrid Name="chatRoomsGridView" Margin="0,41,10,0"> <DataGrid.Columns> <DataGridTextColumn Header="Room name" Binding="{Binding Path='RoomName'}" IsReadOnly="True" /> <DataGridTextColumn Header="Users in room" Binding="{Binding Path='UsersAmount'}" IsReadOnly="True" /> <DataGridTemplateColumn Header="Connect"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ToggleButton x:Name="connectionButton" Click="joinToRoomButton_Click"> <ToggleButton.Style> <Style> <Style.Triggers> <Trigger Property="ToggleButton.IsChecked" Value="False"> <Setter Property="ToggleButton.Content" Value="Connect"></Setter> </Trigger> <Trigger Property="ToggleButton.IsChecked" Value="True"> <Setter Property="ToggleButton.Content" Value="Disconnect"></Setter> </Trigger> </Style.Triggers> </Style> </ToggleButton.Style> </ToggleButton> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
尝试的XAML方案2
<DataGridTemplateColumn Header="Connect"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ToggleButton x:Name="connectionButton" Unchecked="joinToRoomButton_Click" Checked="joinToRoomButton_Click"> <ToggleButton.Style> <Style> <Style.Triggers> <Trigger Property="ToggleButton.IsChecked" Value="False"> <Setter Property="ToggleButton.Content" Value="Connect"></Setter> </Trigger> <Trigger Property="ToggleButton.IsChecked" Value="True"> <Setter Property="ToggleButton.Content" Value="Disconnect"></Setter> </Trigger> </Style.Triggers> </Style> </ToggleButton.Style> </ToggleButton> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
对应C#事件代码
加入房间事件
private async void joinToRoomButton_Click(object sender, RoutedEventArgs e) { try { //Room name from DataGridView Room selectedRoom = ((FrameworkElement)sender).DataContext as Room; CurrentRoom = selectedRoom.RoomName; string message = $"{Username} connected to {CurrentRoom} room"; await connection.InvokeAsync("JoinChatRoom", CurrentRoom); await connection.InvokeAsync("ConnectedToGroup", message, CurrentRoom); chatListBox.Items.Add($"You connected to {CurrentRoom} room"); } catch (Exception ex) { chatListBox.Items.Add(ex.Message); } }
离开房间事件
private async void leftFromRoomButton_Click(object sender, RoutedEventArgs e) { try { Room selectedRoom = (sender as FrameworkElement).DataContext as Room; CurrentRoom = selectedRoom.RoomName; string message = $"{Username} is disconnected from {CurrentRoom} room"; await connection.InvokeAsync("LeaveChatRoom", CurrentRoom); await connection.InvokeAsync("ConnectedToGroup", message, CurrentRoom); chatListBox.Items.Add($"You disconnected from {CurrentRoom} room"); } catch (Exception ex) { chatListBox.Items.Add(ex.Message); } }
解决方法
核心问题是未将ToggleButton的IsChecked状态与Room实体的属性绑定,DataGrid的虚拟化或上下文刷新会导致按钮状态重置。通过绑定状态+区分事件逻辑可解决:
1. 给Room类添加绑定属性
在Room类中实现INotifyPropertyChanged接口,添加IsConnected布尔属性用于状态绑定:
public class Room : INotifyPropertyChanged { private bool _isConnected; public string RoomName { get; set; } public int UsersAmount { get; set; } public bool IsConnected { get => _isConnected; set { if (_isConnected != value) { _isConnected = value; OnPropertyChanged(nameof(IsConnected)); } } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
2. 修改ToggleButton的XAML绑定
将IsChecked双向绑定到Room的IsConnected属性,分别绑定Checked和Unchecked到独立事件:
<DataGridTemplateColumn Header="Connect"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ToggleButton x:Name="connectionButton" IsChecked="{Binding IsConnected, Mode=TwoWay}" Checked="JoinToRoomButton_Checked" Unchecked="LeaveFromRoomButton_Unchecked"> <ToggleButton.Style> <Style TargetType="ToggleButton"> <Setter Property="Content" Value="Connect"/> <Style.Triggers> <Trigger Property="IsChecked" Value="True"> <Setter Property="Content" Value="Disconnect"/> </Trigger> </Style.Triggers> </Style> </ToggleButton.Style> </ToggleButton> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
3. 调整事件处理逻辑
事件中利用绑定的状态,操作失败时回滚按钮状态,确保UI与数据一致:
private async void JoinToRoomButton_Checked(object sender, RoutedEventArgs e) { var toggleBtn = sender as ToggleButton; var selectedRoom = toggleBtn.DataContext as Room; if (selectedRoom == null) return; try { CurrentRoom = selectedRoom.RoomName; string message = $"{Username} connected to {CurrentRoom} room"; await connection.InvokeAsync("JoinChatRoom", CurrentRoom); await connection.InvokeAsync("ConnectedToGroup", message, CurrentRoom); chatListBox.Items.Add($"You connected to {CurrentRoom} room"); selectedRoom.IsConnected = true; } catch (Exception ex) { chatListBox.Items.Add(ex.Message); toggleBtn.IsChecked = false; } } private async void LeaveFromRoomButton_Unchecked(object sender, RoutedEventArgs e) { var toggleBtn = sender as ToggleButton; var selectedRoom = toggleBtn.DataContext as Room; if (selectedRoom == null) return; try { CurrentRoom = selectedRoom.RoomName; string message = $"{Username} is disconnected from {CurrentRoom} room"; await connection.InvokeAsync("LeaveChatRoom", CurrentRoom); await connection.InvokeAsync("ConnectedToGroup", message, CurrentRoom); chatListBox.Items.Add($"You disconnected from {CurrentRoom} room"); selectedRoom.IsConnected = false; } catch (Exception ex) { chatListBox.Items.Add(ex.Message); toggleBtn.IsChecked = true; } }
4. 额外注意事项
- 确保DataGrid的
ItemsSource绑定Room对象集合,每个Room实例初始化IsConnected属性; - 若DataGrid开启虚拟化,需保证
INotifyPropertyChanged接口正确触发,避免滚动时状态丢失。
内容的提问来源于stack exchange,提问作者Death_Dealer
相关产品推荐
相关产品推荐

