【问题标题】:WPF, Caliburn Micro and Dapper - Datagrid Checkbox bindingWPF、Caliburn Micro 和 Dapper - Datagrid 复选框绑定
【发布时间】:2020-02-05 08:24:45
【问题描述】:

我在 WPF 项目中使用 Caliburn Micro 和 Dapper,我在其中创建了一个 DataGrid,我用 SQL Server 数据库表中的数据填充它。请考虑以下代码 sn-ps:

ChangesModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PTSRDesktopUI.Models
{
    //public class for all changes attributes
    public class ChangesModel
    {
        public int ID { get; set; }
        public string Facility { get; set; }
        public string Controller { get; set; }
        public string ParameterName { get; set; }
        public string OldValue { get; set; }
        public string NewValue { get; set; }
        public DateTime ChangeDate { get; set; }
        public bool Validated { get; set; }
        public DateTime ValidationDate { get; set; }
    }
}

OverviewView.xaml

<!--Datagrid Table-->
<DataGrid Grid.Row="1" x:Name="Changes" CanUserAddRows="False" AutoGenerateColumns="False" HorizontalAlignment="Stretch">
    <DataGrid.Columns>
        <DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True" 
                            Header="Facility" Binding="{Binding Path=Facility}"/>
        <DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True" 
                            Header="Controller" Binding="{Binding Path=Controller}"/>
        <DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True" 
                            Header="Parameter" Binding="{Binding Path=ParameterName}"/>
        <DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True" 
                            Header="Old Value" Binding="{Binding Path=OldValue}"/>
        <DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True" 
                            Header="New Value" Binding="{Binding Path=NewValue}"/>
        <DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True" 
                            Header="Changed Date" Binding="{Binding Path=ChangeDate, 
                            StringFormat='{}{0:dd.MM HH:mm}'}"/>
        <DataGridTemplateColumn CellStyle="{StaticResource DataGridCellCentered}" 
                                Header="Validated" IsReadOnly="True">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate >
                    <CheckBox IsChecked="{Binding Path=Validated}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True" 
                            Header="Validation Date" Binding="{Binding Path=ValidationDate, 
                            StringFormat='{}{0:dd.MM HH:mm}'}"/>
        <DataGridTemplateColumn CellStyle="{StaticResource DataGridCellCentered}" Header="Validate">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button x:Name="Validate_Btn" cal:Message.Attach="Validate">Validate</Button>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

OverviewViewModel.cs

using Caliburn.Micro;
using PTSRDesktopUI.Helpers;
using PTSRDesktopUI.Models;

namespace PTSRDesktopUI.ViewModels
{
    public class OverviewViewModel : Screen
    {

        //Create new Bindable Collection variable of type ChangesModel
        public BindableCollection<ChangesModel> Changes { get; set; }


        public OverviewViewModel()
        {

            //Create connection to DataAccess class
            DataAccess db = new DataAccess();

            //get the changes from DataAccess function and store them as a bindable collection in Changes
            Changes = new BindableCollection<ChangesModel>(db.GetChanges());

        }

        //Validate_Btn click event
        public void Validate()
        {
           //Some Code        
        }

    }
}

DataAccess.cs

//Function to get all changes from database using stored procedures
public List<ChangesModel> GetChanges()
{
    using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(DBHelper.CnnVal("ptsrDB")))
    {
        var output = connection.Query<ChangesModel>("dbo.getChanges").ToList();
        return output;
    }
}

我使用名为getChanges 的存储过程从 SQL Server 获取数据。数据显示出来,一切正常。我现在想做的是: 首先,我希望 Validate_Btn 仅在未选中 CheckBox 的行上可见。其次,如果用户单击Validate_Btn,我想将CheckBox 更改为选中,使按钮不可见并使用DataAccess 类中的存储过程触发一个新函数,以更新Validated 中的布尔值数据库表。有人知道我该怎么做吗?

【问题讨论】:

    标签: c# wpf mvvm dapper caliburn.micro


    【解决方案1】:

    要解决第一部分根据是否选中CheckBox来显示和隐藏Button,你应该首先在你的ChangesModel类中实现INotifyPropertyChanged接口,并在出现PropertyChanged事件时引发PropertyChanged事件Validated 属性已设置:

    public class ChangesModel : INotifyPropertyChanged
    {
        public int ID { get; set; }
        public string Facility { get; set; }
        public string Controller { get; set; }
        public string ParameterName { get; set; }
        public string OldValue { get; set; }
        public string NewValue { get; set; }
        public DateTime ChangeDate { get; set; }
    
        private bool _validated;
        public bool Validated
        {
            get { return _validated; }
            set { _validated = value; NotifyPropertyChanged(); }
        }
    
        public DateTime ValidationDate { get; set; }
    
        public event PropertyChangedEventHandler PropertyChanged; 
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    
    }
    

    然后您可以将ButtonVisibility 属性绑定到Validated 源属性并使用转换器在bool 值和Visibility 枚举值之间进行转换:

    <DataGridTemplateColumn Header="Validate">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <DataTemplate.Resources>
                    <BooleanToVisibilityConverter x:Key="converter" />
                </DataTemplate.Resources>
                <Button x:Name="Validate_Btn" cal:Message.Attach="Validate"
                        Visibility="{Binding Validated, Converter={StaticResource converter}}">Validate</Button>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    

    您可能还想在CheckBox 绑定上设置UpdateSourcePropertyTrigger,以便立即设置源属性:

    <CheckBox IsChecked="{Binding Path=Validated, UpdateSourceTrigger=PropertyChanged}" />
    

    为了让您的Validate() 在您单击按钮时被调用,您可以将Bind.Model 附加属性绑定到视图模型:

    <Button x:Name="Validate"
            cal:Bind.Model="{Binding DataContext, 
                RelativeSource={RelativeSource AncestorType=DataGrid}}">Validate</Button>
    

    组合绑定需要指定Visibility绑定的来源:

    <Button x:Name="Validate"
        Visibility="{Binding DataContext.Validated, 
           Converter={StaticResource converter}, RelativeSource={RelativeSource AncestorType=DataGridCell}}"
        cal:Bind.Model="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGrid}}">Validate</Button>
    

    【讨论】:

    • 非常感谢您的回答。这对可见性问题非常有效。您知道如何在 ViewModel 的 Validate() 函数中切换 CheckBox 的布尔值吗?我不希望用户能够选中或取消选中列中的复选框,而是通过 Validate Button 对其进行检查并且无法再次取消选中它。
    • @Rei:那你不能禁用 CheckBox 吗?
    • 我尝试在DataGridTemplateColumn 中使用IsReadOnly="True",但它似乎不起作用。但即使我设法禁用它,我仍然需要在单击验证按钮时更改 CheckBox 值。
    • @Rei:这应该只是设置相应的Validated 属性的问题。
    • @Rei:在实际的 CheckBox 元素上将 IsHitTestVisible 设置为 false 以禁用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-29
    • 1970-01-01
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 1970-01-01
    • 2020-05-22
    相关资源
    最近更新 更多