2012-02-26 49 views
0

我有如下所述的類結構。使用「僅獲取」靜態屬性作爲綁定源

//On the design aspects, I know It may not be the advisable approach, 
//but something of this kind is only required. 

/// <summary> 
/// Paper Class 
/// </summary> 
public class Paper 
{ 
    public string PaperName { get; set; } 
    public bool IsPending { get; set; } 
} 

/// <summary> 
/// PaperChecking class, Individual papers will be processed here. 
/// </summary> 
public class PaperChecking 
{ 

    public static List<Paper> ListPapers { get; set; } 

    public static void AddPapers() 
    { 
     ListPapers = new List<Paper>(); 

     ListPapers.Add(new Paper() { PaperName = "Paper1", IsPending = false }); 
     ListPapers.Add(new Paper() { PaperName = "Paper2", IsPending = false }); 
     ListPapers.Add(new Paper() { PaperName = "Paper3", IsPending = false }); 
     ListPapers.Add(new Paper() { PaperName = "Paper4", IsPending = false }); 
     ListPapers.Add(new Paper() { PaperName = "Paper5", IsPending = false }); 
    } 

    public static bool IsCheckingPending 
    { 
     get 
     { 
      //List has items and it is not null, so intentionally removed the checks. 
      return ListPapers.Count(paper => paper.IsPending == true) > 0 ? true : false; 
     } 
    } 
} 

/// <summary> 
/// This class will select papers for processing 
/// </summary> 
public class ChangePaperSetting 
{ 
    public void SelectPaper(string paperName) 
    { 
     //It can be assumed that Paper object will never be NULL 
     PaperChecking.ListPapers.FirstOrDefault(paper => paper.PaperName.Equals(paperName)).IsPending = true; 

    } 
} 

現在, 我想用財產PaperChecking.IsCheckingPending在我的WPF窗口中顯示的一些控制。我與我的控件的可見性綁定了相同的屬性。預計第一次窗口加載行爲時,因爲Collection已經存在。但是,當時我改變如下Paper對象的掛起狀態運行時:

ChangePaperSetting changePaperSetting = new ChangePaperSetting(); 
    changePaperSetting.SelectPaper("Paper1"); 
    changePaperSetting.SelectPaper("Paper2"); 
    changePaperSetting.SelectPaper("Paper5"); 

在我的收藏,現在我已經IsPending爲真論文。因此,現在PaperChecking.IsCheckingPending將返回TRUE,並根據我的控件應該現在可見。

在一個普通的對象中,我可以實現INotifyPropertyChanged,但在上面的情況下,我沒有屬性上的Setter。有沒有這樣做的方法或任何其他使用相同的類結構的簡潔方法。

//-------------------------------------------------------------------------------// 

更新

正如喬希建議,我想是這樣的:

/// <summary> 
/// Paper Class 
/// </summary> 
public class Paper : INotifyPropertyChanged 
{ 
    public string PaperName { get; set; } 
    private bool isPending; 

    public bool IsPending 
    { 
     get 
     { 
      return isPending; 
     } 
     set 
     { 
      if (isPending != value) 
      { 
       isPending = value; 
       PropertyChanged(this, new PropertyChangedEventArgs("IsPending")); 
      } 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

/// <summary> 
/// PaperChecking class, Individual papers will be processed here. 
/// </summary> 
public class PaperChecking : Control 
{ 

    public static List<Paper> listOfPapers { get; set; } 

    public static bool IsCheckingPending 
    { 
     get 
     { 
      //List has items and it is not null, so intentionally removed the checks. 
      try 
      { 
       return listOfPapers.Count(paper => paper.IsPending == true) > 0 ? true : false; 
      } 
      catch (Exception ex) { return false; } 
     } 
    } 


    public static event PropertyChangedEventHandler PropertyChanged; 
    public static void PendingStatusChanged(object sender,PropertyChangedEventArgs e) 
    { 
     if (e.PropertyName == "IsPending") 
     {     
      //If I keep it static, It given Null Reference Error 
      //and If I implement INotifyPropertyChanged interface 
      //in this Class, it gives compilation error because 
      //I am doing so in my Static property. 

      PropertyChanged(null,new PropertyChangedEventArgs("IsCheckingPending")); 
     } 
    } 

} 

/// <summary> 
/// This class will select papers for processing 
/// </summary> 
public class ChangePaperSetting 
{ 
    public static void AddPapers() 
    { 

     var listOfPapers = new List<Paper>(); 
     for (int i = 0; i < 5; i++) 
     { 
      var paper = new Paper() { PaperName = "Paper"+i.ToString(), 
             IsPending = false }; 
      paper.PropertyChanged+=PaperChecking.PendingStatusChanged; 
      listOfPapers.Add(paper); 
     } 
     PaperChecking.listOfPapers = listOfPapers; 
    } 
    public void SelectPaper(string paperName) 
    { 
     //It can be assumed that Paper object will never be NULL 
     PaperChecking.listOfPapers.FirstOrDefault(paper => paper.PaperName.Equals(paperName)).IsPending = true; 
    } 
} 

這是我的XAML代碼:

<Window xmlns:my="clr-namespace:LearningWpf" x:Class="LearningWpf.Window4" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window4" Height="300" Width="300"  
    > 
<Window.Resources> 
    <my:PaperChecking x:Key="paperChecking"/> 
    <BooleanToVisibilityConverter x:Key="bvc" /> 
</Window.Resources> 
<StackPanel> 
    <Button Name="btn1" Content="Button1" Height="20" Width="80" Click="btn1_Click"></Button> 
    <Button Name="btn2" Content="Button2" Height="20" Width="80" Click="btn2_Click"></Button> 
    <Button Name="btn3" Content="Button3" Height="20" Width="80" 
      Visibility="{Binding Source={StaticResource paperChecking}, 
         Path=IsCheckingPending, 
         Converter={StaticResource bvc}}"></Button> 
</StackPanel> 

這裏是我的CodeBehind.c s

public partial class Window4 : Window 
{ 
    public Window4() 
    { 
     InitializeComponent(); 
    } 

    private void btn1_Click(object sender, RoutedEventArgs e) 
    { 
     ChangePaperSetting.AddPapers(); 

    } 

    private void btn2_Click(object sender, RoutedEventArgs e) 
    { 
     var v = PaperChecking.listOfPapers.FirstOrDefault(paper => 
       paper.PaperName == "Paper1"); 
     v.IsPending = true; 
    } 
} 

但是這段代碼給出了錯誤,righlty,因爲我使用了靜態變量而沒有初始化它。如果有任何更正或任何其他方法來實現相同的目標。非常感謝您的幫助。

回答

0

偏離主題,但爲什麼PaperChecking中的所有屬性和函數都是靜態的?

要解決您的問題,請在PaperChecking中添加一個新功能並實施INotifyPropertyChanged

public void SelectPaper(string paperName) 
{ 
    var paper = ListPapers.FirstOrDefault(paper => paper.PaperName.Equals(paperName)); 
    if (paper != null) 
    { 
     paper.IsPending = true; 
     PropertyChanged("IsCheckingPending"); 
    } 
} 

我假設你知道如何實現INotifyPropertyChanged,並且有自己的引發事件的方式。沒有什麼說你必須從一個財產的設置者那裏提出這個事件。

每次查詢時,讓您的財產吸氣劑循環遍歷整個論文列表是非常非常低效的。它可以並且會被非常頻繁地調用。與任何鼠標或鍵盤事件相當。每次在紙張上更改暫掛狀態時,都應嘗試緩存計數值。這將需要更多的工作,但它可能是值得的。

編輯:

實際上對象可以從多個接口進行更新,他們將不會調用相同的方法,他們有參考PAPER對象,將直接更新,而不是在PaperChecking類調用方法屬性,

在這種情況下,您應該在Paper類上實現INotifyPropertyChanged,然後在PaperChecking內偵聽這些更新。

public void PaperChanged(object sender, PropertyChangedEventArgs args) 
{ 
    if (args.PropertyName == 'IsPending') PropertyChanged("IsCheckingPending"); 
} 

public void AddPapers() 
{ 
    ListPapers = new List<Paper>(); 

    ListPapers.Add(new Paper() { PaperName = "Paper1", IsPending = false }); 
    ListPapers.Add(new Paper() { PaperName = "Paper2", IsPending = false }); 
    ListPapers.Add(new Paper() { PaperName = "Paper3", IsPending = false }); 
    ListPapers.Add(new Paper() { PaperName = "Paper4", IsPending = false }); 
    ListPapers.Add(new Paper() { PaperName = "Paper5", IsPending = false }); 
    foreach(var paper in ListPapers) 
    { 
     paper.PropertyChanged += PaperChanged; 
    } 
} 

您還需要改造PaperChecking到使用實例的方法和屬性,而不是靜態的一類。如果你還不知道MVVM,我建議reading up on it。本質上,你要做的是創建一個PaperChecking的實例,並將其設置爲代碼背後的視圖中的DataSource。然後,在你的XAML,你可以簡單地綁定是這樣的:用WPF起步時

<Button Name="btn3" Content="Button3" Height="20" Width="80" 
    Visibility="{Binding IsCheckingPending, Converter={StaticResource bvc}}" /> 

靜態屬性和方法幾乎總是錯的。知道何時需要使用它們,以及何時嘗試讓自己更容易。

+0

其實我想過這樣做,但沒有。更新屬性的接口在這裏很大,並且在我的對象屬性的生命週期中會經常更改。 – AjayK 2012-02-26 11:21:13

+0

實際上,Objects可以從多個接口更新,它們不會調用相同的方法,它們引用PAPER對象並直接更新屬性,而不是調用PaperChecking類中的方法。如果情況確實如此,那麼這個問題就相當簡單直接的實施。 – AjayK 2012-02-26 11:44:34

+0

無論何時何地添加新紙張,我都必須分配此處理程序。但同一個集合正在跨越多個接口進行更新,這似乎相當困難。有沒有其他的選擇依賴性屬性。 – AjayK 2012-02-26 13:14:46

0

由於您使用的是CLR屬性,所以它有義務通知UI,底層綁定屬性已更改,只能通過從代碼中引發PropertyChanged事件來實現。 首先使集合爲ObservableCollection,因爲它實現INotifyCollectionChanged和INotifyPropertyChanged。與您的收藏掛鉤的收集改變事件和處理程序簡單地提高PropertyChanged事件對你的財產這樣的 -

ObservableCollection<Paper> listOfPapers = new ObservableCollection<Paper>(); 
listOfPapers.CollectionChanged += new NotifyCollectionChangedEventHandler(listOfPapers_CollectionChanged); 

void listOfPapers_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
{ 
     OnPropertyChanged("IsCheckingPending"); 
} 

通過這種方法,你將不必擔心,如果你需要從方法中添加集合中的項目除SelectPaper()外。

其他可能的解決方案本來可以用Dependency Property代替普通的CLR屬性,這樣你就不用擔心引起顯式改變的屬性。

http://msdn.microsoft.com/en-us/library/ms752914.aspx

+0

如果更改列表項目的屬性,但僅在更改集合時才能使用。 – 2012-02-26 12:44:09

+0

@RV和Josh說的一樣,我並沒有改變這裏的收藏,而是作品。我正在尋找使用依賴屬性的替代方案。我試圖使用,但我有問題是否在Paper類或PaperChecking類上使用依賴項屬性。如果您有任何參考,請在那裏重定向我。感謝Thanx的幫助。 – AjayK 2012-02-26 13:12:37

0

這樣的事情,也許呢?

private static bool _isCheckingPending; 
public static bool IsCheckingPending 
{ 
    get 
    {    
     bool pending = ListPapers.Count(paper => paper.IsPending == true) > 0; 

     if (pending != _isCheckingPending) 
     { 
      PropertyChanged("IsCheckingPending"); 
      _isCheckingPending = pending; 
     } 

     //List has items and it is not null, so intentionally removed the checks. 
     return _isCheckingPending; 
    } 
} 

的想法是,它會記住結果從最後一次,如果從結果不同,這一次,提高PropertyChanged事件(當然,你會AVE實施INotifyPropertyChanged的)。

+0

但是在靜態屬性中不允許實現PropertyChanged事件。任何解決方法。 – AjayK 2012-02-26 13:24:20

+0

並且最重要的是,只有當有人試圖訪問該值時,纔會調用GET。這裏底層集合中的對象已經被改變了,之後它應該被調用。這是我的問題。底層收集如何通知它已經改變。 – AjayK 2012-02-26 13:37:28