如何在WPF / c#中订购事件处理?

时间:2017-08-29 10:54:45

标签: c# wpf events

我正在开发符合MVVM模式的cardgame。我的模型包含玩家,手和牌以及游戏及其规则。 这里有2个课程不好看:" card"有#"已提交"事件:当玩家点击卡片的图像时,提交的事件会触发。这会触发UI将卡从手移动到窗口的中心。 接下来我有一个"技巧",所有玩家都添加一张卡片。当技巧已满时,它会触发TrickFull事件:这会触发UI以显示技巧中的牌,然后清除表格。

在游戏过程中,TrickFull事件在最后一张卡提交后会触发纳秒。这意味着在显示第4张卡之前清除该表。我希望能够强制UI在Trickfull事件之前处理cardsubmitted事件。 我试图通过Thread.Sleep(这不起作用)来实现这一点,我也尝试将TrickFull事件移动到游戏类(意味着它会在稍后被触发)。这有效,但看起来确实不合适。我已经研究了锁定事件(但这似乎没有办法),直接控制Dispatcher,更改优先级,或者可能异步调用事件并在EndInvoke中以某种方式阻塞这些事件。 我想知道最好的解决办法是什么。我的研究表明,事件可能不是这种行为的最佳模式,但我很难过。请问有光明的人请告诉我如何解决这个(可能是建筑性的)缺陷?

下面的代码,要注意:荷兰的类名和内容

卡(= Kaart)

public class Kaart : IComparable<Kaart>
{
    public readonly Kleur Kleur;
    public readonly Waarde Waarde;

    public Kaart(Kleur kleur, Waarde waarde)
    {
        Kleur = kleur;
        Waarde = waarde;
    }

    public event KaartGespeeld Opgegooid;
    public delegate void KaartGespeeld(Kaart kaart);

    public void Opgooien()
    {
        Opgegooid?.Invoke(this);
    }

    public int CompareTo(Kaart other)
    {
        var comparer = new KlaverjasComparer(null, null);
        return comparer.Compare(this, other);
    }

    public Speler Speler { get; set; }
}

Trick(= Slag)

 public class Slag
    {
        private readonly List<Kaart> _kaarten;

        [Browsable(false)]
        public IReadOnlyList<Kaart> Kaarten => _kaarten;

        public Slag(Kleur troef)
        {
            _kaarten = new List<Kaart>(4);
            Troef = troef;
        }

        public Speler Winnaar { get; private set; }

        public int Punten => PuntenTeller.Punten(this);

        public int Roem => PuntenTeller.Roem(this);

        [Browsable(false)]
        public Kleur Troef { get; }

        public Kleur GevraagdeKleur { get; set; }

        [Browsable(false)]
        public bool Vol =>_kaarten.Count == 4;


        public void Add(Kaart kaart)
        {
            if (!Vol)
            {
                if (_kaarten.Count == 0)
                {
                    GevraagdeKleur = kaart.Kleur;
                }

                _kaarten.Add(kaart);
            }
            else
            {
                throw new Exception("Te veel kaarten in een slag");
            }

            if (!Vol) return;

            Winnaar = bepaalHoogsteKaart(this).Speler;

            VolleSlag?.Invoke(this);
        }

        public event SlagIsVol VolleSlag;
        public delegate void SlagIsVol(Slag slag);

    }

视图模型:

    public TafelViewModel(Boompje boompje)
    {
        Speler1 = boompje.Deelnemers[0];
        Speler2 = boompje.Deelnemers[1];
        Speler3 = boompje.Deelnemers[2];
        Speler4 = boompje.Deelnemers[3];
        Troef = boompje.Potje.Troef;

        //boompje.SlagIsVol += Boompje_SlagIsVol;
        // ToDo: als ik naar dit event kijk gaat het mis 

        boompje.Potje.Slag.VolleSlag += Boompje_SlagIsVol;
        boompje.Potje.TroefGedraaid += delegate { Troef = boompje.Potje.Troef; };

        foreach (Speler _deelnemer in boompje.Deelnemers)
        {
            foreach (Kaart _kaart in _deelnemer.Hand)
            {
                _kaart.Opgegooid += moveKaart;
            }
            _deelnemer.DoeIkHet += DeelnemerOnDoeIkHet;
        }

        _spelerKaart = new Dictionary<Speler, string>
        {
            {Speler1, "Kaart1"},
            {Speler2, "Kaart2"},
            {Speler3, "Kaart3"},
            {Speler4, "Kaart4"}
        };

        _spelerRichting = Dictionary.SpelersRichting(boompje.Deelnemers);
        WinnaarVisible = Visibility.Hidden;
    }

    private void Boompje_SlagIsVol(Slag slag)
    {
        WinnaarVisible = Visibility.Visible;
        Richting = _spelerRichting[slag.Winnaar];

        Application.DoEvents();
        Thread.Sleep(2000);
        Kaart1 = null;
        Kaart2 = null;
        Kaart3 = null;
        Kaart4 = null;
        WinnaarVisible = Visibility.Hidden;          

    }


    private void moveKaart(Kaart kaart)
    {
        PropertyInfo prop = GetType().GetProperty(_spelerKaart[kaart.Speler]);
        prop?.SetValue(this, kaart);
    }

    public void OpKaartGeklikt(Kaart kaart)
    {
        if (kaart.Speler != Speler3)
        {
            return;
        }

        Speler3.SpeelKaart(kaart);
    }

}

}

1 个答案:

答案 0 :(得分:0)

在ViewModel中设置ManualResetEvent

ManualResetEvent manualResetEvent = new ManualResetEvent(false);

将此对象传递给您的Kaart

ManualResetEvent _manualResetEvent;
public Kaart(Kleur kleur, Waarde waarde, ManualResetEvent manualResetEvent)
{
    Kleur = kleur;
    Waarde = waarde;
    _manualResetEvent = manualResetEvent;
}

这是在添加卡时调用的方法我假设

public void Opgooien()
{
    Opgegooid?.Invoke(this);
    _manualResetEvent.Set();
}

主要部分(您还需要将ManualResetEvent传递给Slag对象。

public void Add(Kaart kaart)
{
    if (!Vol)
    {
        if (_kaarten.Count == 0)
        {
            GevraagdeKleur = kaart.Kleur;
        }

        _kaarten.Add(kaart);
    }
    else
    {
        throw new Exception("Te veel kaarten in een slag");
    }

    if (!Vol) return;

    Winnaar = bepaalHoogsteKaart(this).Speler;
    var result = _manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));
    if(!result)
    {
        /* Did not receive signal in 5 seconds */
    }
    VolleSlag?.Invoke(this);
    _manualResetEvent.Reset();
}

只是基本概念,由于您的代码语言并且在示例中缺少某些部分,它可能无法正常工作,但您应该抓住这个想法