代码之家  ›  专栏  ›  技术社区  ›  Infii

如何使用Caliburn Micro从DataGrid选定行设置ViewModel属性

  •  -1
  • Infii  · 技术社区  · 6 年前

    我正在使用Caliburn Micro处理一个WPF(MVVM)应用程序,我使用了属性中应驻留在VM中的标准字,在我的应用程序中,我有3个文本框和一个数据报,我想要的是每当使用选择任何行时,文本框必须显示所选值(仅限单个选择!),文本框将根据列显示不同的数据。我也为相同的结构建模,问题是我已经按照cm的命名约定将控件的x:name设置为属性,现在从模型中进行选择,这样我如何从模型属性中设置本地vm属性。

    我的模型:

    public class PackageModel
    {
        public int id { get; set; }
        public string sessionName { get; set; }
        public int sessionInMins { get; set; }
        public int sessionAmount { get; set; }
        public bool isActive { get; set; }
    }
    

    我的ViewModel:

    private string _packName;
        public string PackageName
        {
            get { return _packName; }
            set
            {
                _packName = value;
                NotifyOfPropertyChange(() => PackageName);
            }
        }
    
        private int _amount;
        public int Amount
        {
            get { return _amount; }
            set {
                _amount = value;
                NotifyOfPropertyChange(() => Amount);
            }
        }
    
        private int _mins;
        public int Mins
        {
            get { return _mins; }
            set {
                _mins = value;
                NotifyOfPropertyChange(() => Mins);
            }
        }
    
        private bool _isActive;
        public bool IsPackageActive
        {
            get { return _isActive; }
            set {
                _isActive = value;
                NotifyOfPropertyChange(() => IsPackageActive);
            }
        }
    
        private List<PackageModel> _packageList;
        public List<PackageModel> PackageList
        {
            get { return _packageList; }
            set
            {
                _packageList = value;
                NotifyOfPropertyChange(() => PackageList);
            }
        }
    
        private PackageModel _selectedPackage;
        public PackageModel SelectedPackage
        {
            get
            {
                return _selectedPackage;
            }
            set
            {
                    _selectedPackage = value;
                    NotifyOfPropertyChange(() => SelectedPackage);
            }
            }
        }
    

    我的看法是:

    <!--ROW 1-->
        <TextBox 
            x:Name="PackageName"
            Width="210" 
            Margin="5 5"
            Controls:TextBoxHelper.Watermark="Package Name"
            Controls:TextBoxHelper.ClearTextButton="True"
            HorizontalAlignment="Left"
            Grid.Row="0" 
            Grid.Column="0"/>
    
        <!--ROW 2-->
        <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal">
            <TextBox
                x:Name="Mins"
                Width="100" 
                Margin="5 5"
                Controls:TextBoxHelper.Watermark="Min(s)"
                Controls:TextBoxHelper.ClearTextButton="True"/>
            <TextBox Width="100"
                     x:Name="Amount"
                     Margin="5 5"
                     Controls:TextBoxHelper.Watermark="Amount"
                     Controls:TextBoxHelper.ClearTextButton="True"/>
            <CheckBox 
                x:Name="IsPackageActive" 
                Margin="5 5" 
                Content="Is Active?" 
                IsChecked="{Binding SelectedPackage.isActive}"/>
        </StackPanel>
    
        <!--ROW 3-->
        <DataGrid x:Name="PackageList" 
                  SelectedItem="{Binding SelectedPackage, Mode=TwoWay}"
                  Grid.Row="2"
                  Grid.ColumnSpan="1"
                  AutoGenerateColumns="False"
                  CanUserAddRows="False"
                  CanUserDeleteRows="False"
                  CanUserSortColumns="False"
                  CanUserReorderColumns="False"
                  CanUserResizeRows="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="ID" Binding="{Binding id}" Visibility="Hidden" IsReadOnly="True"/>
                <DataGridTextColumn Header="Name" Binding="{Binding sessionName}" Width="120" IsReadOnly="True"/>
                <DataGridTextColumn Header="Min(s)" Binding="{Binding sessionInMins}" IsReadOnly="True"/>
                <DataGridTextColumn Header="Amount" Binding="{Binding sessionAmount}" IsReadOnly="True"/>
                <DataGridCheckBoxColumn IsReadOnly="True" Header="Is Active?" Binding="{Binding isActive}" Width="*"/>
            </DataGrid.Columns>
        </DataGrid>
    

    请建议我是否遵循了错误的标准或设置属性的错误方法。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Kaspar    6 年前

    这不是Calibro,但你说没问题。

    我删除了sessionmins和sessionamout属性以缩短答案,您可以像添加其他属性一样添加它。

    首先,我将inotifypropertychanged添加到模型中,还为属性(大写)创建pascalcase。帕斯卡酶是不需要的,但它是最常见的约定。

    public class PackageModel : INotifyPropertyChanged
        {
            private int _Id;
            public int Id
            {
                get { return _Id; }
                set
                {
                    if (value != _Id)
                    {
                        _Id = value;
                        NotifyPropertyChanged();
                    }
                }
            }
    
            private string _SessionName;
            public string SessionName
            {
                get { return _SessionName; }
                set
                {
                    if (value != _SessionName)
                    {
                        _SessionName = value;
                        NotifyPropertyChanged();
                    }
                }
            }
    
            private bool _IsActive;
            public bool IsActive
            {
                get { return _IsActive; }
                set
                {
                    if (value != _IsActive)
                    {
                        _IsActive = value;
                        NotifyPropertyChanged();
                    }
                }
            }
    
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    

    我将vm修改为只有包列表和selectedpackage,从名称包中删除列表并使其成为复数外接程序。还可以创建一些默认的构造函数来填充开发人员列表。正如您所建议的,现在不需要额外的属性,稍后只需使用selectedpackage。

        public class MainViewModel : INotifyPropertyChanged
        {
            public MainViewModel()
            {
                Packages = new List<PackageModel>()
                {
                    new PackageModel()
                    {
                        Id = 1, SessionName="Session1", IsActive = true
                    },
                    new PackageModel()
                    {
                        Id = 2, SessionName="Session2", IsActive = false
                    }
                };
            }
    
            private PackageModel _SelectedPackage;
            public PackageModel SelectedPackage
            {
                get { return _SelectedPackage; }
                set
                {
                    if (value != _SelectedPackage)
                    {
                        _SelectedPackage = value;
                        NotifyPropertyChanged();
                    }
                }
            }
    
            private List<PackageModel> _Packages;
            public List<PackageModel> Packages
            {
                get { return _Packages; }
                set
                {
                    if (value != _Packages)
                    {
                        _Packages = value;
                        NotifyPropertyChanged();
                    }
                }
            }
    
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    

    并添加视图。进行手动绑定。当您更改网格中的项目时,文本框和复选框将自动更新,如果您更改文本框或复选框中的值,它也将更新数据报。

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBox Width="210" Margin="5 5" HorizontalAlignment="Left" Grid.Row="0" Grid.Column="0" Text="{Binding SelectedPackage.SessionName, Mode=TwoWay}"/>
        <StackPanel Grid.Row="1">
            <CheckBox Margin="5 5" Content="Is Active?" IsChecked="{Binding SelectedPackage.IsActive, Mode=TwoWay}"/>
    
        </StackPanel>
        <DataGrid ItemsSource="{Binding Packages,Mode=TwoWay,NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged }" 
              SelectedItem="{Binding SelectedPackage, Mode=TwoWay}"
              Grid.Row="2"
              AutoGenerateColumns="False"
              CanUserAddRows="False"
              CanUserDeleteRows="False"
              CanUserSortColumns="False"
              CanUserReorderColumns="False"
              CanUserResizeRows="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="ID" Binding="{Binding Id}" Visibility="Hidden" IsReadOnly="True"/>
                <DataGridTextColumn Header="Name" Binding="{Binding SessionName}" Width="120" IsReadOnly="True"/>
                <DataGridCheckBoxColumn IsReadOnly="True" Header="Is Active?" Binding="{Binding IsActive}" Width="*"/>
            </DataGrid.Columns>
        </DataGrid>
    
    </Grid>
    

    如果解决方案对您有效,请通知我!

        2
  •  0
  •   mm8    6 年前

    你可以把 Text 属性显式转换为相应的源属性(并移除 Amount 属性),例如:

    <TextBox Width="100" x:Name="Amount" Margin="5 5" Text="{Binding SelectedPackage.sessionAmount}" />
    

    或者可以在视图模型中设置相应的源属性:

    private PackageModel _selectedPackage;
    public PackageModel SelectedPackage
    {
        get
        {
            return _selectedPackage;
        }
        set
        {
            _selectedPackage = value;
            NotifyOfPropertyChange(() => SelectedPackage);
            if (_selectedPackage != null)
            {
                Amount = _selectedPackage.sessionAmount;
                //...
            }
            else
            {
                Amount = default(int);
            }
        }
    }