我有如下所述的课程结构。
//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对象的Pending状态,如下所示:
ChangePaperSetting changePaperSetting = new ChangePaperSetting();
changePaperSetting.SelectPaper("Paper1");
changePaperSetting.SelectPaper("Paper2");
changePaperSetting.SelectPaper("Paper5");
在我的收藏中,现在我的论文中有IsPending为真。所以现在PaperChecking.IsCheckingPending将返回TRUE,并且根据我的控件现在应该可见。
在普通对象中,我可以实现INotifyPropertyChanged,但在上面的情况下,我没有在属性上设置Setter。有没有办法做这个或任何其他整齐的方法使用相同的类类结构。
//-------------------------------------------------------------------------------//
更新
正如Josh所说,我尝试过这样的事情:
/// <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.cs
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;
}
}
但是这段代码给出了错误,因为我在不初始化的情况下使用静态变量。如果有任何更正或任何其他方法来实现相同的目标。非常感谢您的帮助。
答案 0 :(得分: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上更改挂起状态时,都应尝试缓存计数值。这将需要更多的工作,但它可能值得做。
编辑:
实际上对象可以从多个接口更新,并且它们不会调用相同的方法,它们引用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
的实例,并将其设置为View后面代码中的DataSource
。然后,在您的XAML中,您可以像这样绑定:
<Button Name="btn3" Content="Button3" Height="20" Width="80"
Visibility="{Binding IsCheckingPending, Converter={StaticResource bvc}}" />
使用WPF开始时,静态属性和方法几乎总是错误的。知道什么时候需要使用它们,以及何时尝试让自己更容易。
答案 1 :(得分: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属性,这样您就不必担心提升显式更改的属性。
答案 2 :(得分: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事件(当然你也会实现INotifyPropertyChanged)。