我正在用Caliburn Micro开发一个WPF(MVVM)应用程序,我遵循标准的措辞,即属性应驻留在VM中,在我的应用程序中,我有3个文本框和一个datagrid,我想要的是在使用时选择“文本框”必须显示所选值的任何行(“仅单选!”),“文本框”将根据“列”显示不同的数据。我也为相同的结构建模,问题是我已经按照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>
请建议我是否遵循任何错误的标准或错误的属性设置方式。
答案 0 :(得分:1)
这些不是Calibro,但您说没关系。
我删除了sessionInMins和sessionAmout属性,以缩短答案,您可以像其他属性一样添加它。
首先,我将INotifyPropertyChanged添加到Model,我还为属性创建PascalCase(大写字母)。 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));
}
}
并添加视图。进行手动装订。当您更改网格中的项目时,文本框和复选框将自动更新,如果更改文本框或复选框中的值,它也会同时更新DataGrid。
<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>
让我知道解决方案是否适合您!
答案 1 :(得分:0)
您可以将Text
属性显式绑定到适当的source属性(并从视图模型中删除Amount
属性),例如:
<TextBox Width="100" x:Name="Amount" Margin="5 5" Text="{Binding SelectedPackage.sessionAmount}" />
或者您可以在视图模型中设置相应的source属性:
private PackageModel _selectedPackage;
public PackageModel SelectedPackage
{
get
{
return _selectedPackage;
}
set
{
_selectedPackage = value;
NotifyOfPropertyChange(() => SelectedPackage);
if (_selectedPackage != null)
{
Amount = _selectedPackage.sessionAmount;
//...
}
else
{
Amount = default(int);
}
}
}