好吧我是C ++开发人员,目前我正在研究WPF应用程序,看起来这是一个棘手的情况。我动态地生成了一组按钮,标签等文本框和按钮彼此绑定。我之前用C ++代码完成了这个,现在我需要在WPF应用程序中完成它。
XAML:
<ListBox x:Name="myViewChannelList" HorizontalAlignment="Stretch" Height="Auto" ItemsSource="{Binding VoltageCollection}" Margin="0" VerticalAlignment="Stretch" Width="Auto" >
<ListBox.Resources>
<convert:BooleanToVisibilityConverter x:Key="booltovisibility"/>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate >
<Grid Visibility="{Binding IsAvailable, Converter={StaticResource booltovisibility}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="170" />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding ChannelName}" Margin="50,20,0,0"></Label>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding VoltageText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="25" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="170,20,0,0" />
<Button Grid.Column="1" Content="Set" Height="25" CommandParameter="{Binding VoltageText}" Command="{Binding VoltageCommand}" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20,20,0,0" ></Button>
</Grid>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
视图模型:
private ICommand m_voltageCommand;
public ChannelList()
{
m_voltageCommand = new DelegateVoltageCommand(x => SetCommandExecute(x));
}
public void Initialize()
{
VoltageCollection = new ObservableCollection<VoltageModel> { new VoltageModel() { ChannelName = "", IsAvailable = false, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
new VoltageModel() { ChannelName = "VDD__Main", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
new VoltageModel() { ChannelName = "VDD__IO__AUD", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
new VoltageModel() { ChannelName = "VDD__CODEC__AUD", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand }
};
}
ObservableCollection<VoltageModel> _voltages;
public ObservableCollection<VoltageModel> VoltageCollection
{
get
{
return _voltages;
}
set
{
_voltages = value;
OnPropertyChanged("VoltageCollection");
}
}
// Event when SET Button is clicked
public void SetCommandExecute(object voltageText)
{
string value = voltageText.ToString();
int val = Convert.ToInt32(value);
}
因此它生成按钮+文本框+标签3次,如Initialize()
方法所示。现在VoltageCommand = m_voltageCommand
为我提供了在文本框中输入的文本,并调用SetCommandExecute(object voltageText)
方法,其中voltageText为我提供输入的值。
型号:
string voltageText = string.Empty;
public string VoltageText
{
get
{
return voltageText;
}
set
{
voltageText = value;
OnPropertyChanged("VoltageText");
}
}
**C++ Code:**
// Since we have 3 channels, channel maintains count
if(button == m_setButton[channel])
{
unsigned cmd = 0x0300;
int numBytes = 0;
cmd |= (channel & 0xFF);
// Some code
此处它告诉用户点击了哪个按钮并获取channe
l的值,即如果点击了第二个按钮,则channel = 2
。
这里我需要实现用C ++编写的代码。如何获取频道,即单击了哪个按钮。看看cmd |= (channel & 0xFF);
,它使用channel
值。如何在我的应用程序中实现它?
答案 0 :(得分:2)
您只需将一个ID属性添加到您的VoltageBoardChannel类。
int index ;
public int ID
{
get
{
return index;
}
set
{
index = value;
OnPropertyChanged("ID");
}
}
然后将CommandParameter Binding更改为CommandParameter="{Binding}"
而不是CommandParameter="{Binding VoltageText}"
,您现在不仅会收到Text,还会收到现在拥有ID的VoltageBoardChannel Class实例。
在您的Command Execute方法
中public void DoSomethingExecute(object param)
{
VoltageBoardChannel result = param as VoltageBoardChannel;
string value = result.VoltageText;
int index = result.ID;
}
答案 1 :(得分:1)
这是你对MVVM的基本问题:
ViewModel永远不应该知道View;它应该可以独立于任何View元素
进行测试在您的SetCommandExecute方法中,期望从View发送一些基于工作的文本。如果你要为SetCommandExecute方法编写单元测试,只使用ViewModel其他部分的信息,你会传递什么?
相反,您的SecCommandExecute应为:
SetCommandExecute(object voltageModel)
{
VoltageModel myModel = voltageModel as VoltageModel; // Cast the model to the correct object type
if (myModel != null)
{ // myModel will be null of voltageModel is not a VoltageModel instance
// TODO: Whatever work you need to do based on the values of the myModel
}
}
您的XML应为:
<Button Grid.Column="1" Content="Set" Height="25" CommandParameter="{Binding }" Command="{Binding VoltageCommand}" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20,20,0,0" ></Button>
这是如何工作的?那么它归结为DataContext。由于网格中每一行的DataContext都是一个VoltageModel,因此您可以直接绑定到它的多个属性。示例Text="{Binding VoltageText ...}"
datagrid中的每个项都有一个每行对象实例的隐含DataContext。由于每一行都绑定到一个VoltageModel实例,因此您可以直接在代码中使用该事实。 View知道它正在使用哪些ViewModel属性和实例,并且可以向下传递给ViewModel用户所采取行动的特定VoltageModel。
推理:
当您的命令事件运行时,它应该传入VoltageModel对象,这使您可以直接访问所有实例属性。请记住,这是最佳实践,因为您希望能够对SetCommandExecute
方法进行单元测试,而无需在某些文本中传递视图,解析它,在视图上找到某些控件以及所有这些内容。
简而言之:ViewModel应该是完全独立的,并且能够根据ViewModel可用的数据运行所有单元测试。
答案 2 :(得分:0)
我自己只做了一点WPF。当我将数据绑定到控件时,我可以通过某种方式将该数据项与其他数据项区别开来。
伪代码:
private void Button_Clicked(object sender, EventArgs e) {
MyType obj = (MyType)listView1.SelectedItem[0];
if (obj.UniqueItem == whatINeed) {
DoStuffFunction();
}
}
我不知道这是否适合您的情况,但这就是我解决问题的方法。
答案 3 :(得分:0)
您已经将电压文本框绑定到属性,因此不需要将该值作为命令参数传递。相反,您可以将源指定为命令:
<Button CommandParameter="TheButton" />
在命令处理程序的实现中:
public void SetCommandExecute(object source)
{
string source = source as string;
if (source == "TheButton")
{
int val = Convert.ToInt32(this.VoltageText);
}
}
答案 4 :(得分:0)
Hi而不是将VoltageText绑定到CommandParameter,将Button绑定到它,你可以从ButtonDataContext中获取VoltageText或者将ListBox的SelectedItem绑定到ViewModel属性。我希望这会有所帮助。
<ListBox x:Name="lb">
<ListBoxItem>
<Button x:Name="btn" CommandParameter="btn" Command="{Binding MyCommand}" VerticalAlignment="Bottom" Height="30"/>
</ListBoxItem>
<ListBoxItem>
<Button CommandParameter="{Binding SelectedIndex, ElementName=lb}" Command="{Binding MyCommand}" VerticalAlignment="Bottom" Height="30"/>
</ListBoxItem>
</ListBox>
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private ICommand _myCommand;
public ICommand MyCommand { get { return _myCommand ?? (new CommandHandler((o) => FireCommand(o),()=> true)); } }
public void FireCommand(object obj)
{
var a = lb.SelectedIndex;
}
public class CommandHandler:ICommand
{
private Action<object> del;
public CommandHandler(Action<object> action, Func<bool> b=null)
{
del = action;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
del(parameter);
}
#endregion
}
您可以尝试使用以上两种方法之一。