2016-07-19 72 views
0

我將UserControl與ItemsControl綁定爲ObservableCollection。這個ItemsControl中的DataTemplate是一個包含TextBox和Button的Grid。使用MVVM在WPF中動態添加連接UIElements

下面是一些代碼(更新):

<UserControl.Resources> 
    <entities:SeparatingCard x:Key="IdDataSource"/> 
</UserControl.Resources> 
<ItemsControl ItemsSource="{Binding Cards}"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition/> 
        <ColumnDefinition/> 
       </Grid.ColumnDefinitions> 
       <Grid.RowDefinitions> 
        <RowDefinition/> 
       </Grid.RowDefinitions> 
       <TextBox Text="{Binding Id, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" GotFocus="TextBox_GotFocus" Grid.Row="0" Grid.Column="0"/> 
       <Button DataContext="{Binding Source={StaticResource IdDataSource}}" Command="{Binding Accept}" Grid.Row="0" Grid.Column="1">Accept</Button> 
      </Grid> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

在模型文件:

public ObservableCollection<SeparatingCard> Cards { get; set; } 

卡類:

class SeparatingCard : INotifyPropertyChanged 
{ 
    private string _id; 
    public string Id 
    { 
     get { return _id; } 
     set 
     { 
      _id = value; 
      OnPropertyChanged("Id"); 
     } 
    } 
    public ActionCommand Accept { get; } 
    public SeparatingCard() 
    { 
     Accept = new ActionCommand(AcceptCommandExecute); 
    } 
    private void AcceptCommandExecute(object obj) 
    { 
     MessageBox.Show(Id); 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

卡在運行時添加的,我動態地獲得新的文本框按鈕對在我的UserControl中。現在在每一對中,我需要做以下事情:
- 能夠檢查文本框中的文本是否正確,並禁用/啓用適當的按鈕。
- 在按鈕上單擊從適當的文本框中獲取文本並對其進行處理。

我想通過MVVM完成所有這些工作。但我只是來解決方案,直接訪問UI和實現的只是第二個任務:

private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     var text = (((sender as Button).Parent as Grid).Children 
      .Cast<UIElement>() 
      .First(x => Grid.GetRow(x) == 0 && Grid.GetColumn(x) == 0) as TextBox).Text; 
     MessageBox.Show(text); 
    } 

更新
至於有人建議我嘗試ICommand邏輯移動到SeparatingCard類。現在它總是返回null,我不能檢查我的命令引用的類的SeparatingCard的對象。更新在上面的代碼中。

+1

那麼,你有什麼特別的麻煩?您的集合中應該有一個視圖模型,並帶有文本的ID值。該視圖模型也會有一個'ICommand',你可以綁定到'Button.Command'屬性。相同的視圖模型可以檢查什麼是「正確的」,並相應地更改'ICommand'的'CanExecute()'值。這些都不需要訪問UI元素;它都在視圖模型中。如果您需要所有幫助,請提供一個很好的[mcve],以清楚地顯示您嘗試過的內容,並精確說明您需要哪些幫助。 –

+0

奇怪的是,您正在使用elvis操作符,但仍未利用'nameof()'或更好的[CallerMemberName](https://msdn.microsoft.com/en-us/library/system.runtime。 compilerservices.callermembernameattribute.aspx)屬性。 – Will

+0

就我個人而言,我會切換到使用'ICommand',因此要執行的代碼位於ViewModel中,但是如果您確實想使用'Click'方法,則可以投射該按鈕的'.DataContext':'var data =((Button)sender).DataContext as SeparatingCard;' – Rachel

回答

1

而不是使用Button.Click,使用Button.Command,您可以綁定到SeparatingCard中的某個命令。

請在本教程一看: http://www.codeproject.com/Tips/813345/Basic-MVVM-and-ICommand-Usage-Example

然後,SeparatingCard視圖模型將包含可以綁定到Button.Command一個ICommand對象。 所以如果用戶點擊按鈕,事件將被引導到相應的SeparatingCard對象的命令。

+0

我是mvvm的新手,但我實際上在我的項目中使用了命令。我只是沒有得到如何我可以將命令從按鈕綁定到將使用其文本框操作的功能。 – SHKVal

+0

當用戶點擊按鈕時,該命令將觸發SeparatingCard內的功能。在那裏您可以引用與TextBox綁定的Id字段。 – OrMiz

+0

感謝您的解決方案,但現在'Id'屬性始終爲空。請檢查代碼更新。可能是我在那裏犯了一些錯誤。 – SHKVal