You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 17:55:18