2012-02-26 52 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