未能绑定动态生成的按钮& WPF中的文本框

时间:2012-10-10 05:10:17

标签: c# wpf button dynamic mvvm

我正在WPF应用程序中动态生成标签,按钮和文本框。好吧,我成功地动态创建它们,但我面临着一个主要问题。

的Xaml:

<ListBox x:Name="myViewChannelList" HorizontalAlignment="Stretch" Height="Auto" ItemsSource="{Binding}" Margin="0" VerticalAlignment="Stretch" Width="Auto">
            <ListBox.ItemTemplate>
                <DataTemplate >
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="170" />
                            <ColumnDefinition />                                
                        </Grid.ColumnDefinitions>

                        <Label Grid.Column="0" Content="{Binding Path=ChanelName}" Margin="50,20,0,0"></Label>

                        <Grid Grid.Column="1">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>
                            <TextBox Grid.Column="0" Text="{Binding Path=VoltageText}" Height="25" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" />
                            <Button Grid.Column="1" Content="Set" Height="25" Command="{Binding ElementName=myViewChannelList, Path=DataContext.SetCommand}" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" ></Button>
                        </Grid>                            
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
</ListBox>

模特课程:

private string _ChanelName = "";
public String ChanelName
    {
        get
        {
            return _ChanelName;
        }

        set
        {
            if (value != _ChanelName)
            {
                _ChanelName = value;
                OnPropertyChanged("ChanelName");                    
            }
        }            
    }

    // Constructor
    public VoltageModel(string ChanelName)
    {
        this.ChanelName = ChanelName;            
    }

    public override string ToString()
    {
        return _ChanelName;
    }

ViewModel类:

class ChannelList : ObservableCollection<VoltageModel>, INotifyPropertyChanged
{
   private string _VoltageText;
    public string VoltageText
    {
        get { return _VoltageText; }
        set
        {
            _VoltageText = value;
            OnPropertyChanged("VoltageText");
        }
    }       

    // Method gets called when Set Button Is Clicked
    public void SetCommandExecuted()
    {
        string val = VoltageText;
    }

    //Notify Property Changed members are present
}

Xaml.cs课程:

ChannelList myChanels = new ChannelList();                        

public VoltageView() // Constructor
{
     InitializeComponent();            
     myChanels.Add(new VoltageModel("VDD__Main"));
     myChanels.Add(new VoltageModel("VDD__IO__AUD"));
     myChanels.Add(new VoltageModel("VDD__CODEC__AUD"));                      
     myViewChannelList.DataContext = myChanels;            
}  

当我运行应用程序时,这给了我3个标签(上面的内容),3个文本框和3个按钮。

现在,当我在文本框中输入值时,当我在SetCommandExecuted()中放置断点时,它会在按钮单击时显示null。最重要的是,我单击的4个按钮中的任何一个都会生成事件。我希望第一个文本框和第一个按钮同步(绑定),第二个textbx和第二个按钮同步,依此类推。基本上每个控件必须与一行中的另一个控件同步。它不应该影响其他行。可能吗???

2 个答案:

答案 0 :(得分:3)

以下是您问题的解决方案。作为一般惯例,您希望避免所有逻辑,在后面的代码中构建数据等。所有业务逻辑都应该在视图模型中,这样可以更容易进行单元测试。

这是视图

<强>的.xaml

<StackPanel>
    <ListBox HorizontalAlignment="Stretch" 
             Height="Auto" 
             ItemsSource="{Binding VoltageCollection}"
             VerticalAlignment="Stretch" 
             Width="Auto">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Label Width="100" 
                           Content="{Binding ChannelName}" />
                    <TextBox Width="100" 
                             Text="{Binding VoltageText}" />
                    <Button Margin="10,0,0,0" 
                            Content="Set" 
                            Command="{Binding VoltageCommand}" 
                            CommandParameter="{Binding VoltageText}" />
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</StackPanel>

以下是

背后的代码

<强> .xaml.cs

    private ChannelListViewModel m_voltageViewModel;
    public MainWindow()
    {
        InitializeComponent();

        m_voltageViewModel = new ChannelListViewModel();
        m_voltageViewModel.Initialize();

        DataContext = m_voltageViewModel;
    }

以下是模型: VoltageModel

public class VoltageModel : INotifyPropertyChanged
{
    public string ChannelName { get; set; }

    private string m_voltageText;
    public string VoltageText
    {
        get { return m_voltageText; }
        set 
        { 
            m_voltageText = value;
            OnPropertyChanged("VoltageText");
        }
    }

    public ICommand VoltageCommand { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

以下是ViewModel: ChannelListViewModel

public class ChannelListViewModel
{
    private ICommand m_voltageCommand;
    public ChannelListViewModel()
    {
        m_voltageCommand = new DelegateCommand(x => SetCommandExecute(x));
    }

    public void Initialize()
    {
        VoltageCollection = new ObservableCollection<VoltageModel> { new VoltageModel() { ChannelName = "VDD__Main", VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
                                                                     new VoltageModel() { ChannelName = "VDD__IO__AUD", VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
                                                                     new VoltageModel() { ChannelName = "VDD__CODEC__AUD", VoltageText = String.Empty, VoltageCommand = m_voltageCommand }};
    }

    public ObservableCollection<VoltageModel> VoltageCollection { get; set; }

    public void SetCommandExecute(object voltageText)
    {
        Debug.WriteLine(voltageText);
    }
}

最后简单的DelegateCommand类 DelegateCommand

public class DelegateCommand : ICommand
{
    Action<object> m_executeDelegate;

    public DelegateCommand(Action<object> executeDelegate)
    {
        m_executeDelegate = executeDelegate;
    }

    public void Execute(object parameter)
    {
        m_executeDelegate(parameter);
    }

    public bool CanExecute(object parameter) { return true; }
    public event EventHandler CanExecuteChanged;
}

Screenshot Running

答案 1 :(得分:0)

由于我认识到两件通常非常错误的事情,所以我没有太多了解错误,而且这可能是您出现意外行为的问题。

第一个:您的DataTemplate将您的控件置于另一个之上。

修复:

     <DataTemplate >
            <Grid>
                <Grid.ColumnDefinitions>
                     <ColumnDefinition />
                     <ColumnDefinition />
                     <ColumnDefinition />
                </Grid.ColumnDefinitions>

                <Label Grid.Column="0" Content="{Binding Path=ChanelName}" />
                <TextBox Grid.Column="1" Text="{Binding Path=VoltageText}" />
                <Button Grid.Column="2" Command="{Binding ElementName=myViewChannelList, Path=DataContext.SetCommand}" />
            </Grid>
        </DataTemplate>

第二个:在PropertyChanged事件上升后设置属性,因此在下次输入值之前不会更新它们。

修复:

private T _property;
public T Property
{
    get { return _property; }
    set
    {
        _property = value;
        OnPropertyChanged("Property");
    }
}           

如果您在我的回答中发表评论时仍有问题,请进行这些修改并编辑您的帖子。