我正在编写一个小型音频应用程序(在Silverlight中,但这与我想的并不相关),而且我正在努力解决我之前遇到过的问题并且从未妥善解决过。这次我想做对。
在应用程序中有一个Arrangement控件,其中包含多个Track控件,每个Track都可以包含AudioObject控件(这些都是自定义用户控件)。用户需要能够选择音频对象,并且当选择这些对象时,它们以不同方式呈现。我可以通过挂钩AudioObject控件的MouseDown事件并相应地设置状态来实现这一点。到目前为止一切都很好,但是当选择音频对象时,需要取消选择所有其他音频对象(除非用户持有shift键,否则)。虽然音频对象不了解其他音频对象,但是他们没有办法告诉其他音频对象取消选择。
现在,如果我像上次那样在AudioObject控件的构造函数中传递对Arrangement控件的引用,并且给Arrangement控件一个DeselectAll()方法或者类似的东西,这会告诉我这个问题,这会告诉我所有Track控件取消选择其所有AudioObject控件。这感觉不对,如果我将这个策略应用于类似的问题,恐怕我很快会最终得到每个对象都引用其他所有对象,从而产生一个紧密耦合的大混乱。感觉就像为设计不佳的代码打开闸门一样。
有没有更好的方法来解决这个问题?
答案 0 :(得分:0)
保持某种程度的松散耦合的一种方法是通过事件实现选择通知。正如你所说,AudioObject控件可以在它们的构造函数中接受一个Arrangement控件(或者更好的是,一个IArrangement接口,所以你可以有多个实现稍微更好的解耦),而IArrangement接口可以有一个RaiseItemSelected()方法,它在转动提出了ItemSelected事件。所有AudioObject控件都知道要监听该事件,并且如果它们不是被选中的对象,则会取消选择。
答案 1 :(得分:0)
为什么不通过排列控制来处理选择?将每个AudioObject上的mousedown事件(或者仅通过测试点击位置在排列级别完全处理它)连接到排列中的相同处理程序。然后,您可以为每个AudioObject设置选择视觉效果,然后为发送到处理程序的一个打开它。这样做也可以让你更容易维护像SelectedAudio属性或SelectionChanged事件这样的东西,而不是排列控件用于树。
编辑:我更仔细地重新阅读这个问题,以便更好地了解安排vs track与audioobject控件的内容。看到3层,我肯定会处理所有选择(除非轨道控制还必须执行选择相关的活动)。我会处理排列控件的click事件,当它出现时我会对点击位置进行点击测试,并检查AudioObject是否在堆栈中。如果是,我只是操纵保持在排列级别的选择集合以获得正确的数据(基于键修饰符或其他)。我还要为该选择集合在collectionchanged上设置一个事件处理程序,它循环遍历每个轨道控件中的AudioObjects,并根据它们是否包含在选择集合中来设置它们的视觉效果。设置这样,我也可以通过在选择集合中添加/删除来手动操作代码中的选择(出于我可能需要的任何原因)。