2013-03-28 23 views
0

在WPF中,我有一個ListView的2列,第一列需要是一個按鈕。糾正我,如果我錯了,但我發現在ListView中實現按鈕的唯一方法是使用DataTemplate。我發現這個問題是我沒有辦法維護我的原始按鈕屬性時,他們與DataTemplate映射,所以我被迫使用綁定重新映射每個單獨的屬性(包括自定義屬性,因爲我實際上使用自定義用戶控件從Button繼承)。這似乎無關手動映射所有屬性,所以也許有更好的方法來自動持久這些屬性?DataTemplate在WPF ListView中顯示按鈕,同時保留屬性

這裏是我的測試代碼:

public MainWindow() { 
    InitializeComponent(); 

    ObservableCollection<ScreenRequest> screenRequests = new ObservableCollection<ScreenRequest>() { 
     new ScreenRequest("A", "1"), 
     new ScreenRequest("B", "2") 
    }; 
    myListView.ItemsSource = screenRequests; 
} 

public class ScreenRequest { 
    public CustomButton ScreenButton { set; get; } 
    public string Details { set; get; } 

    public ScreenRequest(string buttonText, string customProperty) { 
     this.ScreenButton = new CustomButton(); 
     this.ScreenButton.Content = buttonText; 
     this.ScreenButton.CustomProperty = customProperty; 
     this.ScreenButton.Click += new RoutedEventHandler(InitiateScreenRequest); 
    } 

    private void InitiateScreenRequest(object sender, RoutedEventArgs e) { 
     CustomButton screenBtn = (CustomButton)sender; 
     screenBtn.Content = "BUTTON TEXT CHANGED"; 
    } 
} 

public class CustomButton : Button { 
    public string CustomProperty { get; set; } 
} 

而XAML:

<Window... 
... 
    <Window.Resources> 
     <DataTemplate x:Key="ButtonTemplate"> 
      <local:CustomButton Content="{Binding ScreenButton.Content}"/> 
     </DataTemplate> 
    </Window.Resources> 
    <Grid x:Name="grdMain"> 
    ... 
     <ListView... 
      <ListView.View> 
       <GridView x:Name="gridView"> 
        <GridViewColumn CellTemplate="{StaticResource ButtonTemplate}" Width="Auto" Header="Screen" HeaderStringFormat="Screen"/> 
        <GridViewColumn Header="Details" HeaderStringFormat="Details" DisplayMemberBinding="{Binding Details}"/> 
       </GridView> 
      </ListView.View> 
     </ListView> 
    </Grid> 
</Window> 

所以我的問題是:

  1. 我必須在的CustomButton每一個屬性手動映射爲了讓它繼承到DataTemplate或是它們的一個全部自動持久化屬性?
  2. 如何在綁定中映射CustomProperty屬性,使其與按鈕保持一致?我爲此使用DependencyProperty?
  3. 如何維護我的點擊事件,使單擊GridView中的按鈕將調用InitiateScreenRequest函數?理想情況下,我希望爲所有按鈕聲明單個方法,但我還沒有得到這一點。

任何幫助或深入瞭解listview按鈕將不勝感激。

+0

有點困惑。按鈕中的哪些屬性是你談論的,以及如何進行矯枉過正,因爲在DataTemplate中,您定義了模板和關聯樣式「once」,然後這些樣式將被重複用於集合中的每個元素。 – Viv

+0

對於這個例子,我只想維護CustomButton的Content,CustomProperty和Click屬性。現在這並不過分,但是在考慮我是否有10多個Properites,並且必須映射它們中的每一個,而不是僅僅是「自動綁定」的方式。 如果我們被迫手動綁定所有東西,我想我知道如何使用DependencyProperty做CustomProperty,但不知道如何通過DataTemplate持久化Click事件。感謝您的評論。 –

+0

老兄,我不知道'Screen'是什麼,但是你的'Data Items'不應該包含'UI Elements'的實例。也就是說,你不能在ViewModel中放置像ScreenButton這樣的東西。 –

回答

2
<Window x:Class="MiscSamples.TonyRush" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="TonyRush" Height="300" Width="300"> 
    <ListView ItemsSource="{Binding}"> 
     <ListView.View> 
      <GridView> 
       <GridViewColumn Width="Auto" Header="Screen" HeaderStringFormat="Screen"> 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <Button Command="{Binding SomeAction}" Content="{Binding ActionDescription}" Width="100"/> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
       <GridViewColumn Header="Details" HeaderStringFormat="Details" DisplayMemberBinding="{Binding Details}" Width="100"/> 
      </GridView> 
     </ListView.View> 
    </ListView> 
</Window> 

代碼背後:

public partial class TonyRush : Window 
    { 
     public TonyRush() 
     { 
      InitializeComponent(); 
      DataContext = new List<ScreenRequest> 
           { 
            new ScreenRequest() {ActionDescription = "Click Me!"}, 
            new ScreenRequest() {ActionDescription = "Click Me Too!"}, 
            new ScreenRequest() {ActionDescription = "Click Me Again!!"}, 
           }; 
     } 
    } 

視圖模型:

public class ScreenRequest: INotifyPropertyChanged 
    { 
     public Command SomeAction { get; set; } 

     private string _actionDescription; 
     public string ActionDescription 
     { 
      get { return _actionDescription; } 
      set 
      { 
       _actionDescription = value; 
       NotifyPropertyChanged("ActionDescription"); 
      } 
     } 

     private string _details; 
     public string Details 
     { 
      get { return _details; } 
      set 
      { 
       _details = value; 
       NotifyPropertyChanged("Details"); 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

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

     public ScreenRequest() 
     { 
      SomeAction = new Command(ExecuteSomeAction) {IsEnabled = true}; 
     } 

     //public SomeProperty YourProperty { get; set; } 

     private void ExecuteSomeAction() 
     { 
      //Place your custom logic here based on YourProperty 
      ActionDescription = "Clicked!!"; 
      Details = "Some Details"; 
     } 
    } 

主要部分:Command類:

//Dead-simple implementation of ICommand 
    //Serves as an abstraction of Actions performed by the user via interaction with the UI (for instance, Button Click) 
    public class Command : ICommand 
    { 
     public Action Action { get; set; } 

     public void Execute(object parameter) 
     { 
      if (Action != null) 
       Action(); 
     } 

     public bool CanExecute(object parameter) 
     { 
      return IsEnabled; 
     } 

     private bool _isEnabled; 
     public bool IsEnabled 
     { 
      get { return _isEnabled; } 
      set 
      { 
       _isEnabled = value; 
       if (CanExecuteChanged != null) 
        CanExecuteChanged(this, EventArgs.Empty); 
      } 
     } 

     public event EventHandler CanExecuteChanged; 

     public Command(Action action) 
     { 
      Action = action; 
     } 
    } 

結果:

enter image description here

注:

看看如何單獨的UI是從數據和功能。這是WPF的方式。切勿將UI與數據/業務代碼混合使用。

ViewModel中的Command作爲Button的抽象。 ViewModel不知道什麼是Button,也不應該。讓我知道你是否需要進一步的細節。

+0

這太棒了。誰沒有通過相關的例子學得最好?我的代碼正在運行,但想要花費接下來的幾個小時真正理解它是如何工作的。我會稍後回覆。非常感謝! :) –

+0

好吧,我理解ViewModel類,但不理解Command類的內部工作,希望隨着時間的推移。 對於我正在處理的項目,我已將您的示例進一步展示,並在每行中顯示項目列表,並且我的列動態生成以綁定到正確的索引。例如。列1的綁定是TheList [0] .Text,列2的綁定是TheList [1] .Text。這很好,我現在唯一的問題是,當我點擊按鈕,它將我帶入包含當前行列表的對象實例,所以我實際上不知道... –

+0

...哪個列(按鈕)被點擊上。我可以與您分享一個Visual Studio解決方案嗎?我想我正在尋找關於我是否要走正確道路或是否需要重新評估我的戰略的意見。我希望這是有道理的。 –