Использование статического свойства «Get Only» в качестве источника привязки - PullRequest
0 голосов
/ 26 февраля 2012

У меня есть структуры классов, как указано ниже.

 //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. Я связал то же свойство с видимостью моих элементов управления. Когда окно загружается в первый раз, ожидается поведение, потому что коллекция уже существует. Но во время выполнения, когда я меняю статус Ожидание объекта «Бумага», как показано ниже:

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

В моей коллекции теперь есть бумаги, в которых IsPending имеет значение true. Так что теперь 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.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;
    }
}

Но этот код выдает ошибку, верно, потому что я использую статическую переменную без ее инициализации. Если есть какая-либо коррекция или любой другой подход для достижения той же цели. Ваша помощь высоко ценится.

Ответы [ 3 ]

0 голосов
/ 26 февраля 2012

Поскольку вы используете свойство CLR, ваша обязанность - уведомить пользовательский интерфейс об изменении базового свойства привязки, что возможно только путем вызова события 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 голосов
/ 26 февраля 2012

Как то так, может быть?

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).

0 голосов
/ 26 февраля 2012

Не по теме, но почему все свойства и функции в 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, и у вас есть свой способ поднять событие. Ничто не говорит о том, что вы должны поднять событие из установщика свойства.

Проведение цикла получения вашего имущества через весь список документов при каждом запросе очень и очень неэффективно. Это можно и будет называть очень и очень часто. В значительной степени с любым событием мыши или клавиатуры. Вы должны пытаться кэшировать значение счетчика каждый раз, когда статус ожидания изменяется на бумаге. Это займет немного больше работы, но это может стоить сделать.

Edit:

На самом деле объекты могут обновляться из нескольких интерфейсов, и они не будут вызывать один и тот же метод, они имеют ссылку на объект PAPER и будут обновлять свойство напрямую, вместо вызова метода в классе PaperChecking

В этом случае вы должны реализовать INotifyPropertyChanged в классе Paper, а затем прослушать эти обновления в 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, я предлагаю читать на нем . По сути, вы должны создать экземпляр PaperChecking и установить его как DataSource в своем коде за представлением. Затем в вашем XAML вы можете просто связать это так:

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

Статические свойства и методы почти всегда неверны при запуске с WPF. Знайте, когда вам нужно их использовать, и когда вы пытаетесь облегчить себе жизнь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...