XAML 无法将复选框绑定到WinUI3中的类的字段

5w9g7ksd  于 2023-09-28  发布在  其他
关注(0)|答案(1)|浏览(100)

我看到了问题WinUI 3 Datagrid Checkbox not Bound when using Template Column and Cell/Data Template,但它是没有答案的,而我甚至无法得到基本水平的问题。
在DataGrid中,我试图创建一组复选框,将选择最多2个项目,而其余的将被取消选中/变灰,直到用户取消选择任何一个。我计划做取消选中和禁用复选框从C#代码,这就是为什么我需要它绑定两种方式。
为了测试,我创建了两个列,尽管我只需要一个可以工作
1.第一个带有DataTemplate和复选框的
1.使用DataGridCheckBoxColumn
看起来像这样:

  • 带有DataTemplate和复选框的第一列在显示端工作正常,但不绑定,即当绑定值(isBowling)以程序方式更改时更改IsChecked。
  • 第二列与DataGridCheckBox仍然禁用,我不知道为什么?

我的XAML代码:

<controls:DataGrid.Columns >
         <controls:DataGridTemplateColumn Header="Select Two">
             <controls:DataGridTemplateColumn.CellTemplate>
                 <DataTemplate >
                     <CheckBox IsChecked="{Binding isBowling ,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Checked="CheckBox_Checked" />
                 </DataTemplate>
             </controls:DataGridTemplateColumn.CellTemplate>
          </controls:DataGridTemplateColumn>
         <controls:DataGridCheckBoxColumn IsReadOnly="False" Header="Select 2" Binding="{Binding isBowling, Mode=TwoWay}"/>

         <controls:DataGridTextColumn IsReadOnly="False" FontSize="10" Header="Name" Binding="{Binding Name}" />
     </controls:DataGrid.Columns>
    </controls:DataGrid>

我尝试在类中使用INotifyPropertyChanged。
绑定到DataGrid的Bowler类

public class Bowler : INotifyPropertyChanged
       {
           public event PropertyChangedEventHandler PropertyChanged;
           public string PlayerID;
           public string Name { get; set; }
           public int Stamina { get; set; }
           public double Overs { get; set; }
           public int Maiden { get; set; }
           public int Runs { get; set; }
           public int Wickets { get; set; }
           public int NoBall { get; set; }
           public int Wides { get; set; }
           public string LastBall { get; set; }
           public bool isBowling
           {
               get { return isBowling; }

           set
           {
               isBowling = value;
               PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(isBowling)));
           }
       }

       public override string ToString()
       {
           return JsonConvert.SerializeObject(this);
       }
       }

当我使用INotifyPropertyChanged时,我得到
堆栈溢出错误在isBowling = value;
当我使用这个方法创建ObservableCollection时,堆栈溢出异常发生,说值的设置被多次完成。

private void FillObservableListBowling(ObservableCollection<Bowler> bowlingTeam, List<Player> teamPlayers)
    {
        Debug.WriteLine("Size of bowler list is " + teamPlayers.Count);
        foreach(Player player in teamPlayers)
        {
            if (!player.BOWLERTYPE.Equals("NA"))
            {
                Bowler bowler = new Bowler();
            bowler.PlayerID = player.PLAYERID;
            bowler.Name = player.PLAYERDISPLAYNAME;
            try
            {
                bowler.Stamina = player.STAMINACARD.Equals("NA") || player.STAMINACARD.Equals("") ? 0 : int.Parse(player.STAMINACARD);
            }
            catch (FormatException ex)
            {

                Debug.WriteLine("Exception happened for " + player.ToString());
            }
            bowler.Overs = 0;
            bowler.Maiden = 0;
            bowler.Runs = 0;
            bowler.Wickets = 0;
            bowler.NoBall = 0;
            bowler.Wides = 0;
            bowler.LastBall = "";
            bowler.isBowling = false;

            bowlingTeam.Add(bowler);
        }
    }          
    }

我尝试在所有地方使用Mode =Two Way,UpdateSourceTrigger=PropertyChanged,但不知何故,这两个(DataTemplate和DataGridCheckBox)似乎都不适合我。
任何帮助将不胜感激,使复选框(要么)工作正常,即。当改变类变量的值时,它应该在复选框中反映出来。

aydmsdu9

aydmsdu91#

您需要使用这样的字段:

private bool isBowling;

public bool IsBowling
{
    get => _isBowling;
    set
    {
        if (_isBowling == value)
        {
            return;
        }

        _isBowling = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsBowling)));
    }
}

但我建议使用CommunityToolkit.Mvvm NuGet包来实现这一点。它使用源代码生成器为您创建样板代码。
在你的例子中,你的代码应该是这样的:

保龄球.cs

public partial class Bowler : ObservableObject
{
    [ObservableProperty]
    private string name = string.Empty;

    [ObservableProperty]
    private bool isEnabled = true;

    [ObservableProperty]
    private bool isBowling;
}

MainPageViewModel.cs

public partial class MainPageViewModel : ObservableObject
{
    public ObservableCollection<Bowler> Bowlers { get; } = new();

    public MainPageViewModel()
    {
        int itemsCount = 10;

        for (int i = 0; i < itemsCount; i++)
        {
            Bowler bowler = new();
            bowler.PropertyChanged += Bowler_PropertyChanged;
            Bowlers.Add(bowler);
        }
    }

    private void Bowler_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName is not nameof(Bowler.IsBowling))
        {
            return;
        }

        if (Bowlers.Count(x => x.IsBowling is true) < 2)
        {
            foreach (Bowler bowler in Bowlers)
            {
                bowler.IsEnabled = true;
            }

            return;
        }

        foreach (Bowler bowler in Bowlers)
        {
            bowler.IsEnabled = bowler.IsBowling is true;
        }
    }
}

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
    }

    public MainPageViewModel ViewModel { get; } = new();
}

MainPage.xaml

<Page
    x:Class="DataGridExample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="using:CommunityToolkit.WinUI.UI.Controls"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:DataGridExample"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Name="RootPage"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">

    <Grid RowDefinitions="Auto,*">
        <StackPanel Orientation="Horizontal" />
        <controls:DataGrid
            Grid.Row="1"
            AutoGenerateColumns="False"
            HeadersVisibility="Column"
            IsReadOnly="False"
            ItemsSource="{x:Bind ViewModel.Bowlers, Mode=OneWay}">
            <controls:DataGrid.Columns>
                <controls:DataGridTemplateColumn>
                    <controls:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate x:DataType="local:Bowler">
                            <CheckBox
                                IsChecked="{x:Bind IsBowling, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                IsEnabled="{x:Bind IsEnabled, Mode=OneWay}" />
                        </DataTemplate>
                    </controls:DataGridTemplateColumn.CellTemplate>
                </controls:DataGridTemplateColumn>
            </controls:DataGrid.Columns>
        </controls:DataGrid>
    </Grid>
</Page>

注意:避免使用DataGridCheckBoxColumn。它有一些约束力或聚焦问题。

相关问题