【发布时间】:2022-10-05 01:15:16
【问题描述】:
我上周问了这个问题(How to Toggle Visibility Between a Button and a Stack Panel Containing Two Buttons),答案很完美,正是我想要的。虽然我意识到我将拥有 3 个用户控件,它们都具有非常相似的元素,所以最好将行拆分为可重用。但是,我很难让控件显示在表单上。
我创建了这个用户控件,DeviceInfoRow.xaml:
这是 XAML:
<UserControl
x:Class=\"StagingApp.Main.Controls.Common.DeviceInfoRow\"
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:common=\"clr-namespace:StagingApp.Presentation.ViewModels.Common;assembly=StagingApp.Presentation\"
d:DataContext=\"{d:DesignInstance Type=common:DeviceInfoRowViewModel}\"
mc:Ignorable=\"d\" >
<StackPanel
Style=\"{StaticResource InfoRowStackPanelStyle}\">
<Label
Style=\"{StaticResource DeviceInfoPropertyLabelStyle}\"
x:Name=\"InfoLabel\" />
<TextBox
Style=\"{StaticResource DeviceInfoTextBoxStyle}\"
x:Name=\"InfoTextBox\" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=\"Auto\" />
</Grid.ColumnDefinitions>
<StackPanel
Orientation=\"Horizontal\"
Grid.Column=\"0\">
<Button
Command=\"{Binding EditCommand, Mode=OneWay}\"
Visibility=\"{Binding IsEditButtonVisible, Converter={StaticResource BoolToVisConverter}}\"
Style=\"{StaticResource DeviceInfoEditButtonStyle}\">
Edit
</Button>
</StackPanel>
<StackPanel
Orientation=\"Horizontal\"
Grid.Column=\"0\"
Visibility=\"{Binding IsEditButtonVisible, Converter={StaticResource BoolToVisConverter}, ConverterParameter=Inverse}\">
<Button
Command=\"{Binding OkCommand, Mode=OneWay}\"
Style=\"{StaticResource DeviceInfoEditOkButtonStyle}\">
OK
</Button>
<Button
Command=\"{Binding CancelCommand, Mode=OneWay}\"
Style=\"{StaticResource DeviceInfoEditCancelButtonStyle}\">
CANCEL
</Button>
</StackPanel>
</Grid>
</StackPanel>
</UserControl>
这是用户控件的 ViewModel:
namespace StagingApp.Presentation.ViewModels.Common;
public partial class DeviceInfoRowViewModel : BaseViewModel
{
private string? _labelText;
public string? LabelText
{
get => _labelText;
set
{
_labelText = value;
OnPropertyChanged(nameof(LabelText));
}
}
private string? _infoTextBox;
public string? InfoTextBox
{
get => _infoTextBox;
set
{
_infoTextBox = value;
OnPropertyChanged(nameof(InfoTextBox));
}
}
private bool _isEditButtonVisible;
public bool IsEditButtonVisible
{
get => _isEditButtonVisible;
set
{
_isEditButtonVisible = value;
OnPropertyChanged(nameof(IsEditButtonVisible));
}
}
[RelayCommand]
public virtual void Ok()
{
IsEditButtonVisible = false;
}
[RelayCommand]
public virtual void Cancel()
{
IsEditButtonVisible = true;
}
[RelayCommand]
public virtual void Edit()
{
IsEditButtonVisible = true;
}
}
BaseViewModel 只是实现 ObservableObject 并继承自 INotifyPropertyChanged。
这就是我目前所拥有的 KitchenInfoView,它将实际显示我的行:
<UserControl
x:Class=\"StagingApp.Main.Controls.InfoViews.KitchenInfoView\"
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:viewmodels=\"clr-namespace:StagingApp.Presentation.ViewModels.InfoViewModels;assembly=StagingApp.Presentation\"
d:DataContext=\"{d:DesignInstance Type=viewmodels:KitchenInfoViewModel}\"
xmlns:local=\"clr-namespace:StagingApp.Main.Controls.Common\"
mc:Ignorable=\"d\"
d:DesignHeight=\"725\"
d:DesignWidth=\"780\"
Background=\"{StaticResource Blue}\">
<Grid Margin=\"20\">
<Grid.ColumnDefinitions>
<ColumnDefinition Width=\"*\" />
<ColumnDefinition Width=\"Auto\" />
<ColumnDefinition Width=\"Auto\" />
<ColumnDefinition Width=\"*\" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height=\"Auto\" />
<RowDefinition Height=\"Auto\" />
<RowDefinition Height=\"Auto\" />
<RowDefinition Height=\"Auto\" />
<RowDefinition Height=\"Auto\" />
<RowDefinition Height=\"Auto\" />
<RowDefinition Height=\"Auto\" />
<RowDefinition Height=\"Auto\" />
<RowDefinition Height=\"Auto\" />
<RowDefinition Height=\"Auto\" />
</Grid.RowDefinitions>
<!-- Title -->
<Label
x:Name=\"ValidationTitle\"
Grid.Row=\"0\"
Grid.Column=\"0\"
Grid.ColumnSpan=\"4\"
Style=\"{StaticResource DeviceInfoTitleStyle}\">
DEVICE VALIDATION
</Label>
<!-- Directions -->
<TextBlock
Grid.Row=\"1\"
Grid.Column=\"0\"
Grid.ColumnSpan=\"4\"
Style=\"{StaticResource TextDirectionStyle}\">
Please confirm that the following information is correct.
If any setting is incorrect, change the value in the text box and select \"Edit\".
The value will then be adjusted. Once all values are correct, press \'OK\'.
The device will then reboot.
</TextBlock>
<!-- Data -->
<StackPanel>
<ItemsControl ItemsSource=\"{Binding Rows}\">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:DeviceInfoRow />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<!-- Buttons -->
<StackPanel
Orientation=\"Horizontal\"
HorizontalAlignment=\"Center\"
Margin=\"0 20 0 0\"
Grid.Row=\"9\"
Grid.Column=\"1\"
Grid.ColumnSpan=\"2\">
<Button
x:Name=\"OK\"
IsDefault=\"True\"
Style=\"{StaticResource DeviceInfoOkButtonStyle}\">
OK
</Button>
<Button
x:Name=\"Cancel\"
IsCancel=\"True\"
Style=\"{StaticResource DeviceInfoCancelButtonStyle}\">
CANCEL
</Button>
</StackPanel>
</Grid>
</UserControl>
最后,KitchenInfoViewModel 现在看起来像这样:
public partial class KitchenInfoViewModel : BaseViewModel
{
[ObservableProperty]
[Description(\"Controller Name\")]
private string? _controllerName;
[ObservableProperty]
[Description(\"Controller Number\")]
private string? _controllerNumber;
[ObservableProperty]
[Description(\"BOH Server Name\")]
private string? _bohServerName;
[ObservableProperty]
[Description(\"TERMSTR\")]
private string? _termStr;
[ObservableProperty]
[Description(\"Key Number\")]
private string? _keyNumber;
[ObservableProperty]
[Description(\"IP Address\")]
private string? _ipAddress;
[ObservableProperty]
[Description(\"BOH IP Address\")]
private string? _bohIpAddress;
private ObservableCollection<DeviceInfoRowViewModel> _rows;
public ObservableCollection<DeviceInfoRowViewModel> Rows
{
get => _rows;
set
{
_rows = value;
OnPropertyChanged();
}
}
public KitchenInfoViewModel()
{
_rows = new ObservableCollection<DeviceInfoRowViewModel>();
var properties = typeof(KitchenInfoViewModel)
.GetProperties();
foreach (var property in properties)
{
var attribute = property.GetCustomAttribute(typeof(DescriptionAttribute));
var description = (DescriptionAttribute)attribute;
_rows.Add(new DeviceInfoRowViewModel()
{
LabelText = description?.Description.ToString(),
InfoTextBox = \"\"
});
}
}
}
我的目标是能够在各种表单上一遍又一遍地使用 DeviceInfoRow,标签的内容来自 VM 中字符串属性的描述。文本框应绑定到每个属性。
这可能吗?我要求太多了吗?我接近了吗?我整天都在用头撞墙。
提前感谢您的帮助。
标签: c# wpf xaml data-binding windows-community-toolkit