2014-01-07 64 views
0

我是新來的MVVM模式,事情非常緩慢地向我走來,我希望能夠點擊我的窗體上的按鈕,然後動態地在運行時創建一個文本框。我有一個「添加標題」和「添加問題」,它們都添加了文本框,但位於不同的位置,您可以在一個標題下添加許多問題。我創建了一個名爲Standard類該類它擁有:綁定ICommand到按鈕?

public class Standard 
{ 
    string _title; 
    ObservableCollection<string> _questions; 
    public event PropertyChangedEventHandler PropertyChanged; 

    #region NofiftyPropChnage 
    protected void NotifyOfPropertyChanged(string name) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 

    protected void NotifyOfPropertyChanged<TProperty>(Expression<Func<TProperty>> property) 
    { 
     NotifyOfPropertyChanged(property.GetMemberInfo().Name); 
    } 
    #endregion 

    #region Properties 
    public string Title 
    { 
     get { return _title; } 
     set 
     { 
      _title = value; 
      NotifyOfPropertyChanged(() => Title); 
     } 
    } 

    public ObservableCollection<string> Questions 
    { 
     get { return _questions; } 
     set 
     { 
      _questions = value; 
      NotifyOfPropertyChanged(() => Questions); 
     } 
    } 
    #endregion 
} 

此類包含一個Title屬性,也問題財產清單,因爲你可以在一個標題添加問題。

我也有一個ViewModel類持有:

class ViewModel :INotifyPropertyChanged 
{ 
    #region NotifyPropertyChange 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected void NotifyOfPropertyChanged(string name) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
} 

protected void NotifyOfPropertyChanged<TProperty>(Expression<Func<TProperty>> property) 
{ 
     NotifyOfPropertyChanged(property.GetMemberInfo().Name); 
} 
    #endregion 

private ObservableCollection<Standard> _standardCollection; 
public ObservableCollection<Standard> StandardCollection 
{ 
     get 
     { 
      return _standardCollection; 
     } 
     set 
     { 
      _standardCollection = value; 
      NotifyOfPropertyChanged(() => StandardCollection); 
     } 
} 
} 

此類包含的標準列表,一個標準是,當你點擊在做文本框中的文本框和信息保存。它保存爲Standard

最後我的XAML代碼:

<Grid> 

<button Content="Add Title"/> 
<button Content="Add Question"/> 

<StackPanel> 
     <ItemsControl ItemsSource="{Binding StandardCollection}"> 
      <ItemsControl.ItemTemplate> 
       <DataTemplate DataType="{x:Type local:Standard}"> 
        <Grid> 
         <TextBox Text="{Binding Title}"/> 
         <ItemsControl ItemsSource="{Binding Questions}"> 
          <ItemsControl.ItemTemplate> 
           <DataTemplate> 
            <TextBox Text="{Binding Questions}"/> 
           </DataTemplate> 
          </ItemsControl.ItemTemplate> 
         </ItemsControl> 
        </Grid> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 
</StackPanel> 


</Grid> 

一切運行並沒有錯誤,但是當我點擊「添加標題」或「添加問題」沒有出現文本框,任何幫助嗎?

回答

1

好吧,我會再出手,在這一個。我已經刪除了標題部分,只是集中討論了這些問題,以便將其作爲一個簡單示例。首先,您需要的是實現INotifyPropertyChanged爲您的視圖模型基類:

public abstract class ObservableObject : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected void OnPropertyChanged<T>(Expression<Func<T>> propertyExpresion) 
    { 
     var property = (MemberExpression)propertyExpresion.Body; 
     this.OnPropertyChanged(property.Member.Name); 
    } 

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

下一步,你需要實現的ICommand您的按鍵綁定到這會導致處理程序時,按下這些按鈕即可稱爲類:

// by Josh Smith, http://msdn.microsoft.com/en-us/magazine/dd419663.aspx 
public class RelayCommand : ICommand 
{ 
    #region Fields 

    readonly Action<object> _execute; 
    readonly Predicate<object> _canExecute; 

    #endregion // Fields 

    #region Constructors 

    public RelayCommand(Action<object> execute) 
     : this(execute, null) 
    { 
    } 

    public RelayCommand(Action<object> execute, Predicate<object> canExecute) 
    { 
     if (execute == null) 
      throw new ArgumentNullException("execute"); 

     _execute = execute; 
     _canExecute = canExecute; 
    } 
    #endregion // Constructors 

    #region ICommand Members 

    public bool CanExecute(object parameter) 
    { 
     return _canExecute == null ? true : _canExecute(parameter); 
    } 

    public event EventHandler CanExecuteChanged 
    { 
     add { CommandManager.RequerySuggested += value; } 
     remove { CommandManager.RequerySuggested -= value; } 
    } 

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

    #endregion // ICommand Members 
} 

這兩個類是別人寫的,如果添加MVVM精簡版項目,你會得到他們爲您提供您的項目。

接下來,我們需要創建一個問題的一個ObservableCollection和被調用處理程序視圖模型,當用戶按下按鈕:

public class MyViewModel : ObservableObject 
{ 
    public ICommand AddQuestionCommand {get; private set;} 

    ObservableCollection<string> _questions = new ObservableCollection<string>(); 
    public ObservableCollection<string> Questions 
    { 
     get { return _questions; } 
     set 
     { 
      _questions = value; 
      OnPropertyChanged(() => Questions); 
     } 
    } 

    public MyViewModel() 
    { 
     this.AddQuestionCommand = new RelayCommand(new Action<object>((o) => OnAddQuestion())); 
    } 

    private void OnAddQuestion() 
    { 
     this.Questions.Add("new item"); 
    } 

} 

顯然,你需要創建一個這樣的實例,並設置它作爲你窗口的DataContext。當命令被觸發時,處理程序被調用,並且它又將一個新的字符串添加到集合中。在XAML現在需要一個按鈕綁定到該命令,並使用問題集合創建顯示他們所有的TextBlocks的列表:

<StackPanel> 
    <Button Content="Add Question" Command="{Binding AddQuestionCommand}" HorizontalAlignment="Left"/> 
    <ItemsControl ItemsSource="{Binding Questions}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <TextBox Text="{Binding .}" Width="200" HorizontalAlignment="Left"/> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</StackPanel> 

這應該可以給你一個起點。如果我錯過了某些東西或者需要澄清任何事情,請發佈後續內容,我會盡我所能。

+0

非常詳細的答案!謝謝。首先,當我點擊添加問題時,我想要出現的是一個'文本框'不寫。其次,當我點擊「添加問題」時,它會出現在頁面的最底部,而不是在Stackpanel的頂部? – user3157821

+0

我更新了XAML以包含帶有EditBox的模板。您仍然需要收集字符串,因爲列表框中的每個元素都需要集合中的相應元素,如果您不想顯示任何文本,則只需用空字符串替換「new item」即可。不知道是什麼原因導致你的底頁對齊,你把這個XAML放在其他可能導致它的東西里面嗎?試着讓它成爲窗口中唯一的東西。 –

+1

感謝您的幫助和代碼,一切正常,我想出瞭如何移動文本框。正確答案。 – user3157821

0

嘗試Standard類實現INotifyPropertyChanged

public class Standard : INotifyPropertyChanged 
{ 
    string _title; 
    ObservableCollection<string> _questions; 
    public event PropertyChangedEventHandler PropertyChanged; 

    #region NofiftyPropChnage 
    protected void NotifyOfPropertyChanged(string name) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 

    protected void NotifyOfPropertyChanged<TProperty>(Expression<Func<TProperty>> property) 
    { 
     NotifyOfPropertyChanged(property.GetMemberInfo().Name); 
    } 
    #endregion 

    #region Properties 
    public string Title 
    { 
     get { return _title; } 
     set 
     { 
      _title = value; 
      NotifyOfPropertyChanged(() => Title); 
     } 
    } 

    public ObservableCollection<string> Questions 
    { 
     get { return _questions; } 
     set 
     { 
      _questions = value; 
      NotifyOfPropertyChanged(() => Questions); 
     } 
    } 
    #endregion 
} 
+0

沒有什麼改變,我需要添加一個命令到我的按鈕在XAML?如果是這樣,什麼? – user3157821

+2

這是如何回答這個問題的? – Sheridan

1

標準需要實現INotifyPropertyChanged接口。通常你不應該多做一次,只要聲明一個實現這些東西的基類,並從中繼承所有的視圖模型。另外,如果您使用包管理器將MVVM Lite添加到您的項目中,那麼您將獲得許多爲您提供的這些內容。

+0

感謝您的回答,我爲我的標準課程添加了'INotifyPropertyChanged',但沒有任何更改,我在XAML中的按鈕中添加了什麼? – user3157821

+0

是的,你需要添加一個ICommand屬性到你的視圖模型,並綁定你的按鈕「命令」屬性,它有更多的信息在[這個SO問題](http://stackoverflow.com/questions/862570/how-可以,我用最relaycommand功能於WPF)。 –

+0

@MarkFeldman我可以看到他們用它來保存,但我需要它來添加一個文本框? – user3157821

1

我不知道爲什麼這些傢伙敲打有關INotifyPropertyChanged接口,爲有這麼很少做ICommand,雖然它似乎你已經嘗試使用它,而不將其添加到Standard類定義。

無論哪種方式,這聽起來像你對我需要使用RelayCommand,或類似的。這是一個擴展ICommand接口的類...你可以把它作爲一個delegate命令。代替定義每個命令一個單獨的類的,可以簡單地定義命令邏輯canExecute處理程序內聯。下面是一個簡單的例子:

public ICommand SaveCommand 
{ 
    get { return new RelayCommand(execute => Save(), canExecute => CanSave()); } 
} 

... 

<Button Content="Save" Command="{Binding SaveCommand}" /> 

你可以找到它在RelayCommand.cs頁面在GitHub上的執行和它在Commands, RelayCommands and EventToCommand頁面上MDSN雜誌的描述。

+0

感謝您的回答,我將需要這個保存按鈕,但添加標題和添加問題按鈕怎麼樣。當我點擊他們不顯示文本框? – user3157821

+2

Sheridan穩定,有時候人們會寫出一個快速回答,指出立即想到的東西,然後在他們有機會更詳細地回答問題時稍後再進行編輯。學習一些耐心......有一點謙卑可能也不會誤入歧途。 –

+0

@ user3157821,什麼?嘗試將上面的* Save *改爲* AddQuestion *,然後你就到了一半。你知道沒有默認的'Save'和'CanSave'方法,不是嗎?這只是您如何從'RelayCommand'調用普通方法的演示。所以,只需創建一個'AddQuestion'方法,然後從'RelayCommand'調用它。閱讀鏈接頁面,瞭解其工作原理的完整說明。 – Sheridan

1

您將需要大量更改代碼才能使其工作。執行以下操作:

步驟1.添加類RelayCommand

public class RelayCommand : ICommand 
{ 
    public Func<bool> CanExecute { get; set; } 
    public Action Execute { get; set; } 

    public RelayCommand() 
    { 
    } 

    public RelayCommand(Action execute) 
    { 
     Execute = execute; 
    } 

    #region ICommand Members 

    bool ICommand.CanExecute(object parameter) 
    { 
     if (this.CanExecute == null) 
     { 
      return true; 
     } 
     else 
     { 
      return this.CanExecute(); 
     } 
    } 

    event EventHandler ICommand.CanExecuteChanged 
    { 
     add { CommandManager.RequerySuggested += value; } 
     remove { CommandManager.RequerySuggested -= value; } 
    } 

    void ICommand.Execute(object parameter) 
    { 
     this.Execute(); 
    } 

    #endregion 
} 

第2步:添加命令在視圖模型

public ICommand AddTitle { get; private set; } 
public ICommand AddQuestion { get; private set; } 

public ViewModel() 
{ 
    _standardCollection = new ObservableCollection<Standard>(); 

    AddTitle = new RelayCommand(OnAddTitle); 
    AddQuestion = new RelayCommand(OnAddQuestion); 
} 

void OnAddTitle() 
{ 
    _standardCollection.Add(new Standard()); 
} 

void OnAddQuestion() 
{ 
    _standardCollection.Last().Questions.Add(new Question("Some Question")); 
} 

步驟3.綁定按鈕

<Button Content="Add Title" Command="{Binding AddTitle}"/> 
<Button Content="Add Question" Command="{Binding AddQuestion}"/> 

您還必須在XAML中解決您的鋪設問題。 由於用戶可以更改問題文本,因此應該創建一個單獨的課題。

+0

感謝您的代碼,非常有幫助需要它! – user3157821