首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >MVVM从绑定到模型类嵌套属性的Textboxes中向DataGrid添加新项

MVVM从绑定到模型类嵌套属性的Textboxes中向DataGrid添加新项
EN

Stack Overflow用户
提问于 2022-01-10 08:32:00
回答 1查看 79关注 0票数 0

我对WPF和MVVM模式都很陌生,我尝试创建一个简单的WPF项目,以查询I-MVVM Profiles的数据库,并通过DataGrid向用户展示。在我成功地完成了它之后,我现在转到下一部分:让用户通过填写一组DataGrid来向TextBoxes添加新的钢型材。

模型

代码语言:javascript
运行
复制
namespace SectionGuardWPF.MVVM.Model
{
    public class IProfileModel : ObservableObject
    {
        #region Private Fields
        public short _recno;
        public string _name;
        public string _staadName;
        public double _ax;
        public double _d;
        public double _bf;
        public double _tf;
        public double _tw;
        public double _iz;
        public double _ix;
        public double _ct;
        public double _iy;
        public double _zx;
        public double _zy;
        #endregion

        #region Public Properties
        /// <summary>
        /// Properties are given NotifyPropertyChanged method to allow for a change in property to be notified
        /// </summary>

        public short RECNO
        {
            get { return _recno; }
            set
            {
                _recno = value;
                OnPropertyChanged();
            }
        }
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChanged();
            }
        }
...
// Repeated for the other fields

ObservableObject:实现ObservableObject的基类

代码语言:javascript
运行
复制
namespace SectionGuardWPF.Core
{
    public class ObservableObject : INotifyPropertyChanged
    {
        /// <summary>
        /// Raised when a property on this object has a new value.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        protected void OnPropertyChanged([CallerMemberName] string name = null) // If you use the CallerMemberName attribute, calls to the NotifyPropertyChanged method don't have to specify the property name as a string argument
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
}

RelayCommand

代码语言:javascript
运行
复制
namespace SectionGuardWPF.Core
{
    class RelayCommand : ICommand
    {
        private Action<object> _execute;
        private Func<object, bool> _canExecute;

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public RelayCommand(Action<object> execute, Func<object,bool> canExecute=null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null || _canExecute(parameter);
        }
        
        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}

视图模型

代码语言:javascript
运行
复制
namespace SectionGuardWPF.MVVM.ViewModel
{
    public class IProfilesViewModel:ObservableObject
    {
        #region Private Fields
        private readonly string _connectionString = //Hidden
        private ObservableCollection<IProfileModel> _iProfiles;
        private ICommand _getIProfilesCommand;
        private ICommand _addNewIProfileCommand;
        private IProfileModel _iProfile = new IProfileModel();
        #endregion

        #region Constructor
        public IProfilesViewModel()
        {
            // Set default Profile Database for the DataGrid upon View instantiation
            IProfiles = GetIProfiles();
        }
        #endregion

        #region Public Properties and Commands
        /// <summary>
        /// Public properties of the IProfilesViewModel Class (used for view binding with IProfilesSubView)
        /// </summary>
        public ObservableCollection<IProfileModel> IProfiles
        {
            get { return _iProfiles; }
            set
            {
                _iProfiles = value;
                OnPropertyChanged();
            }
        }
        public IProfileModel IProfile
        {
            get { return _iProfile; }
            set
            {
                _iProfile = value;
                OnPropertyChanged();
            }
        }
        public ICommand GetIProfilesCommand
        {
            get
            {
                if (_getIProfilesCommand == null)
                {
                    _getIProfilesCommand = new RelayCommand(
                        param => GetIProfiles()
                    );
                }
                return _getIProfilesCommand;
            }
        }
        public ICommand AddNewIProfileCommand
        {
            get
            {
                if (_addNewIProfileCommand == null)
                {
                    _addNewIProfileCommand = new RelayCommand(
                        param => AddNewIProfile()
                    );
                }
                return _addNewIProfileCommand;
            }
        }
        #endregion

        #region Private Methods
        private ObservableCollection<IProfileModel> GetIProfiles()
        {
            TableDataProvider tableDataProvider = new TableDataProvider(_connectionString);
            tableDataProvider.QueryString = "SELECT * FROM [I Shape]";

            IEnumerable<IProfileModel> iProfiles = tableDataProvider.Query<IProfileModel>();
            ObservableCollection<IProfileModel> iProfileObsvCol = new ObservableCollection<IProfileModel>(iProfiles);
            return iProfileObsvCol;
        }

        private void AddNewIProfile()
        {
            IProfiles.Add(
                new IProfileModel
                {
                    RECNO = IProfile.RECNO,
                    Name = IProfile.Name,
                    StaadName = IProfile.StaadName,
                    AX = IProfile.AX,
                    D = IProfile.D,
                    Bf = IProfile.Bf,
                    Tf = IProfile.Tf,
                    Tw = IProfile.Tw,
                    Ix = IProfile.Ix,
                    Iy = IProfile.Iy,
                    Iz = IProfile.Iz,
                    Ct = IProfile.Ct,
                    Zx = IProfile.Zx,
                    Zy = IProfile.Zy
                }
                );
        }

        #endregion
    }
}

视图

代码语言:javascript
运行
复制
<UserControl x:Class="SectionGuardWPF.MVVM.View.IProfilesSubView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:SectionGuardWPF.MVVM.View"
             xmlns:viewModel= "clr-namespace:SectionGuardWPF.MVVM.ViewModel"
             xmlns:view="clr-namespace:SectionGuardWPF.MVVM.View"
             mc:Ignorable="d" 
             d:DesignHeight="580" d:DesignWidth="1300">

    <UserControl.DataContext>
        <viewModel:IProfilesViewModel/>
    </UserControl.DataContext>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="620"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <DataGrid x:Name="ProfilesDataGrid"
                      x:FieldModifier="public"
                      ItemsSource="{Binding IProfiles, Mode=TwoWay}">

        </DataGrid>

        <Border Grid.Column="1"
                CornerRadius="20"
                Background ="White"
                Margin="10">
            <Grid Margin="10">
                <Grid.RowDefinitions>
                    <RowDefinition Height="50"/>
                    <RowDefinition/>
                    <RowDefinition Height="150"/>
                </Grid.RowDefinitions>

                <TextBlock Text="I-Profiles Data Viewer"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Left"
                   Margin="20,0,0,0"
                   Foreground="Black"
                   FontSize="22"/>

                <Grid Grid.Row="1">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>

                    <Grid.RowDefinitions>
                        <RowDefinition/>
                        <RowDefinition/>
                        <RowDefinition/>
                        <RowDefinition/>
                        <RowDefinition/>
                        <RowDefinition/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>

                    <TextBlock Text="RECNO"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="0"
                               Grid.Row="0"
                               FontSize="14"/>

                    <TextBox x:Name="RECNOTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="0"
                             Grid.Row="0"
                             Text="{Binding IProfile.RECNO, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="Name"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="0"
                               Grid.Row="1"
                               FontSize="14"/>

                    <TextBox x:Name="NameTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="0"
                             Grid.Row="1"
                             Text="{Binding IProfile.Name, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="StaadName"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="0"
                               Grid.Row="2"
                               FontSize="14"/>

                    <TextBox x:Name="StaadNameTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="0"
                             Grid.Row="2"
                             Text="{Binding IProfile.StaadName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="AX"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="0"
                               Grid.Row="3"
                               FontSize="18"/>

                    <TextBox x:Name="AXTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="0"
                             Grid.Row="3"
                             Text="{Binding IProfile.AX, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="D"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="0"
                               Grid.Row="4"
                               FontSize="18"/>

                    <TextBox x:Name="DTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="0"
                             Grid.Row="4"
                             Text="{Binding IProfile.D, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="Bf"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="0"
                               Grid.Row="5"
                               FontSize="18"/>

                    <TextBox x:Name="BfTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="0"
                             Grid.Row="5"
                             Text="{Binding IProfile.Bf, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="Tf"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="0"
                               Grid.Row="6"
                               FontSize="18"/>

                    <TextBox x:Name="TfTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="0"
                             Grid.Row="6"
                             Text="{Binding IProfile.Tf, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="Tw"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="1"
                               Grid.Row="0"
                               FontSize="18"/>

                    <TextBox x:Name="TwTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="1"
                             Grid.Row="0"
                             Text="{Binding IProfile.Tw, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="Ix"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="1"
                               Grid.Row="1"
                               FontSize="18"/>

                    <TextBox x:Name="IxTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="1"
                             Grid.Row="1"
                             Text="{Binding IProfile.Ix, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="Iy"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="1"
                               Grid.Row="2"
                               FontSize="18"/>

                    <TextBox x:Name="IyTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="1"
                             Grid.Row="2"
                             Text="{Binding IProfile.Iy, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="Iz"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="1"
                               Grid.Row="3"
                               FontSize="18"/>

                    <TextBox x:Name="IzTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="1"
                             Grid.Row="3"
                             Text="{Binding IProfile.Iz, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="Ct"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="1"
                               Grid.Row="4"
                               FontSize="18"/>

                    <TextBox x:Name="CtTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="1"
                             Grid.Row="4"
                             Text="{Binding IProfile.Ct, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="Zx"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="1"
                               Grid.Row="5"
                               FontSize="18"/>

                    <TextBox x:Name="ZxTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="1"
                             Grid.Row="5"
                             Text="{Binding IProfile.Zx, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

                    <TextBlock Text="Zy"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Left"
                               Margin="20,0,0,0"
                               Foreground="#1A80FA"
                               Grid.Column="1"
                               Grid.Row="6"
                               FontSize="18"/>

                    <TextBox x:Name="ZyTextBox"
                             Margin="0,0,20,0"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Right"
                             Style="{StaticResource ParameterTextbox}"
                             Grid.Column="1"
                             Grid.Row="6"
                             Text="{Binding IProfile.Zy, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
                </Grid>

                <StackPanel Grid.Row="2"
                            Orientation="Horizontal">

                    <Button x:Name="AddButton"
                            Style="{StaticResource AddButton}"
                            Content="Add"
                            Background="#28C941"
                            Height="50"
                            Width="150"
                            Margin="85,0,0,0"
                            Command="{Binding AddNewIProfileCommand}"/>
                    <Button x:Name="EditButton"
                            Style="{StaticResource AddButton}"
                            Content="Edit"
                            Background="#FFBD2E"
                            Height="50"
                            Width="150"
                            Margin="20,0,0,0"/>
                    <Button x:Name="DeleteButton"
                            Style="{StaticResource AddButton}"
                            Content="Delete"
                            Background="#FF6059"
                            Height="50"
                            Width="150"
                            Margin="20,0,0,0"/>

                </StackPanel>
                
            </Grid>
        </Border>
    </Grid>
</UserControl>

我的模型类是一个名为IProfileModel的类,它表示i- from,因此它继承了ObservableObject类,以便它可以使用NotifyPropertyChanged方法,而我创建的类的属性实现了OnPropertyChanged()方法。

在我看来,我已经将DataGrid的源绑定到IProfiles,这是一个存储IProfileModel实例的ObservableCollection。每个TextBox对应于IProfileModel类的一个属性,因此每个TextBox的文本属性绑定到ViewModel的IProfile属性的各自嵌套属性。“添加”按钮绑定到名为“ICommand”的ViewModel中的相应AddNewIProfileCommand

在我的ViewModel中,我使用名称IProfile添加了IProfileModel作为其属性之一,TextBox.Text属性绑定到IProfile的嵌套属性,如视图的XAML所示。至于AddNewIProfileCommand,我已经将其与名为AddNewIProfile()的私有方法相对应,该方法将添加一个新的IProfileModel对象,该对象的属性将引用绑定到TextBoxes的IProfile属性的嵌套属性。

编辑:我想添加AddNewIProfile()将新的IProfileModel对象添加到绑定到DataGrid的IProfiles

我的主要问题是,每当我修改TextBoxes,然后单击Button将概要文件添加到DataGrid,新添加到DataGrid的条目始终是一个带有空属性值的IProfileModel ( IProfileModel的所有字符串属性为null,所有数值类型属性为0)。修改TextBoxes似乎不会改变IProfile的嵌套属性,即使我已经将UpdateSourceTrigger设置为PropertyChangedMode设置为Two WayIProfile本身也属于继承自ObservableObject类的IProfileModel类。

最后,我知道我的问题与这个one非常相似,但我遵循了其中的建议,并试图与它们的解决方案相匹配,但不知何故我无法让它发挥作用。谢谢!

编辑:在按下“添加”按钮后添加一些DataGrid的前后图片:

编辑:Cédric Moers在评论中指出的导致错误的ParameterTextbox风格:

代码语言:javascript
运行
复制
<Style TargetType="{x:Type TextBox}"
           x:Key="ParameterTextbox">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <Border CornerRadius="5"
                            Background="White"
                            Width="180"
                            Height="35"
                            BorderThickness="3"
                            BorderBrush="#EAEAEA">
                        <Grid>
                            <Rectangle StrokeThickness="1"/>
                            <TextBox Margin="1"
                                     Text="{TemplateBinding Text}"
                                     BorderThickness="0"
                                     Background="Transparent"
                                     VerticalContentAlignment="Center"
                                     Padding="5"
                                     Foreground="Black"
                                     x:Name="SearchBox"/>

                            
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-10 09:57:17

我试图复制您的问题,但我不得不删除样式,因为您没有提供它们。它在我身边起作用,所以问题就在风格上?

请删除文本框(ParameterTextbox)的样式,然后查看它是否有效。如果你能为我提供样式的源代码,我可以看看它。也许您正在重写text属性。

编辑后,它的风格是问题的

下面是一个你想以极简的方式完成的风格的例子。

代码语言:javascript
运行
复制
<UserControl.Resources>
    <ControlTemplate x:Key="RoundedTextBoxCt">
        <Border 
            Width="{TemplateBinding Width}"                    
            Height="{TemplateBinding Height}"                                    
            BorderBrush="{TemplateBinding BorderBrush}"              
            BorderThickness="{TemplateBinding BorderThickness}"          
            Background="{TemplateBinding Background}"          
            x:Name="Bd" 
            CornerRadius="5">
            <ScrollViewer
                Padding="{TemplateBinding Padding}"                        
                VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" 
                Foreground="{TemplateBinding Foreground}"
                x:Name="PART_ContentHost"/>
        </Border>
    </ControlTemplate>
    
    <Style x:Key="ParameterTextBox" TargetType="TextBox">
        <Setter Property="Width"                    Value="180"/>
        <Setter Property="Height"                   Value="35"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Padding"                  Value="5"/>
        <Setter Property="Foreground"               Value="Black"/>
        <Setter Property="BorderBrush"              Value="#EAEAEA"/>
        <Setter Property="BorderThickness"          Value="3"/>
        <Setter Property="Background"               Value="White"/>
        <Setter Property="Template" Value="{StaticResource RoundedTextBoxCt}"/>
    </Style>
    
    ...
    
</UserControl.Resources>

我把控件模板作为一个单独的资源,这样“圆角文本框”就可以放在一些“共享”程序集中,您也可以将它用于其他项目。

它是极简主义的,就像你所需要的最低限度。如果您想要一个功能齐全的文本框,从这里复制样式并修改它:https://learn.microsoft.com/en-us/dotnet/desktop/wpf/controls/textbox-styles-and-templates?view=netframeworkdesktop-4.8可能看起来很可怕,但大多数情况下,它只是修改了几个规则。一旦你掌握了它的诀窍,就很容易了。

与其使用setter,甚至不使用单独的控件模板资源,您还可以对控件模板中的所有内容、textbox样式的控件模板的setter中的所有内容进行硬编码,但这取决于您。

祝好运!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70649637

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档