2012-10-10 158 views
1

我正在WPF應用程序中動態生成標籤,按鈕和文本框。那麼我是成功地動態創建它們的,但是我面臨着一個主要問題。無法綁定動態生成的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和第二個按鈕同步,等等。基本上每個控件必須與另一個控件連續同步。它不應該影響其他行。可能嗎???

回答

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)); 
     } 
    } 
} 

這裏是視圖模型: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

+0

令人敬畏的兄弟。這工作順利。但我在這裏幾乎沒有問題。由於您已經對「電壓文本」進行了硬編碼,因此當我嘗試在文本框中輸入某個值並單擊該按鈕時,它仍具有「電壓文本1」值。我希望用戶在文本框中輸入值而不是硬編碼:) – StonedJesus

+0

它只是用「電壓文本1」進行初始化。您可以更改用戶界面上的文本並點擊設置按鈕,它將使用按鈕單擊上的新文本值。只需在每個新的VoltageModel對象上移除VoltageText =「電壓文本」即可。這樣文本框將是空的。 –

+0

檢查我更新的答案。當我這樣做並在文本框中輸入「32」時,我在'SetCommandExecute'處放置了一個斷點,它將對象'voltageText'顯示爲「」並且不帶「32」。我在哪裏犯錯誤? – StonedJesus

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"); 
    } 
}   

使這些修復和編輯您的文章,如果您仍然有問題後我的回答下一個評論。

+0

建議您製作的所有修補程序。也更新了代碼。但問題仍未解決。首先,我在文本框中輸入的值和按鈕單擊不會檢索txtbox值並顯示「null」其次是否可以保持通道名,文本框和按鈕之間的同步?可以說頻道名,tbox&按鈕顯示在第1行,第2行和第3行。每個UI組件在行中應該同步並獨立於其他2 :) – StonedJesus