MVVM模式--游戲地圖編輯器開發(fā)隨筆(3)

相較于上一篇的數(shù)據(jù)綁定問題稼稿,這次也提及相關(guān)的問題苔咪,只不過是在View層面追溯到ViewModel的綁定問題漓概。這次主要是關(guān)于RelayCommand乏屯,以及數(shù)據(jù)綁定的問題根时。

在實際運(yùn)用之中,我們時常需要把一個程序的一個空間包裝成一個用戶控件來單獨(dú)編寫辰晕,再添加到主窗體之中蛤迎,不少這種用戶控件內(nèi)部都需要有指令(Command)來觸發(fā)一系列動作,但是主Model和主ViewModel都在MainWindow的工程之中含友,這就涉及到用戶控件與主窗體在MVVM模式中事件的觸發(fā)與綁定替裆。
首先假設(shè)我們有一個Menu的UserControl,這個用戶控件里面只有一個Menu窘问,然后把這個工程引用到主窗體之中辆童,并且把空間命名為uc,那么它在主窗體的引用如下:

        <uc:MenuControl Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3" 
                        DataContext="{Binding Menu}">
        <!-- Others -->

        </uc:MenuControl>

十分簡單明了的引用惠赫,其中DataContext綁定的MenuControl在主窗體之中的ViewModel把鉴,這個ViewModel負(fù)責(zé)讀取總體的Model以及所有MenuControl的邏輯。
現(xiàn)在架設(shè)一個情況汉形,我們在點擊Menu里的一個MenuItem之后需要出發(fā)一個指令纸镊,改變一個值,并且通知主窗體來完成一些邏輯概疆。在之前的文章中我們已經(jīng)說過逗威,值在用戶控件與主窗體之間的綁定依靠的是暴露成依賴屬性來綁定到主窗體的ViewModel上,通過設(shè)定綁定的Mode來達(dá)到各種效果岔冀,在此就不貼代碼了凯旭。那么問題就來了,UserControl本身就是一個黑盒使套,他自身內(nèi)部的ViewModel實現(xiàn)的邏輯并不能與主窗體進(jìn)行交互罐呼。這個時候采取一個比較巧妙的辦法,我們在UserControl的后臺文件(MenuControl.xaml.cs)后臺定義一個事件侦高,在View中觸發(fā)這個指令的時候我們讓這個指令執(zhí)行這個事件嫉柴,自定義路由事件(RoutedEvent)是與依賴屬性一樣暴露在控件之外的,可以與ViewModel中的屬性綁定奉呛,再通過MVVM模式中EventToCommand標(biāo)簽來把事件轉(zhuǎn)化為指令计螺,再將這個指令與總窗體的ViewModel里的RelayCommand所綁定,就達(dá)到的傳出的目的:

        <uc:MenuControl Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3" 
                        DataContext="{Binding Menu}">
                <i:EventTrigger EventName="EventInMenuControl">
                    <command:EventToCommand Command="{Binding RelayCommandInMainWindow}"></command:EventToCommand>
                </i:EventTrigger>
        </uc:MenuControl>

其中在后臺代碼中定義路由事件:

        public event EventHandler EventInMenuControl
        {
            add { AddHandler(EventInMenuControlEvent, value); }
            remove { RemoveHandler(EventInMenuControlEvent, value); }
        }

        public static readonly RoutedEvent EventInMenuControlEvent = EventManager.RegisterRoutedEvent(
        "EventInMenuControl", RoutingStrategy.Bubble, typeof(EventHandler), typeof(MapEditorControl));

而在綁定到主窗體的RelayCommand的時候有一個MVVM小bug瞧壮,一開始我遇到也是百思不得其解登馒,后來Revert之后逐步復(fù)位才找出。
假設(shè)在主窗體MenuViewModel.cs文件中定義的RelayCommandInMainWindow如下:

    public class MenuViewModel : ViewModelBase
    {
        public RelayCommand RelayCommandInMainWindow { get; set; }
        private XmlDocument File;

        public MenuViewModel()
        {

            RelayCommandInMainWindow = new RelayCommand(() =>
            {
                File = new XmlDocument();
                File.Load("D:\\File.xml");
            });
         }
     }

在這種情況下觸發(fā)這個RelayCommand的時候這個指令并不會被執(zhí)行咆槽,這個是MVVM不支持弱引用的一個BUG陈轿,不能閉包引用外圍變量,需要在內(nèi)部定義秦忿,這個bug在5.4.0中得到了解決麦射,但是5.4.0一直是alpha版本,詳情見MVVM ToolKit灯谣。

===========================================================
接下來繼續(xù)討論MenuControl內(nèi)部的問題法褥,我們在上一篇說過動態(tài)綁定數(shù)據(jù)并顯示的方法,但是運(yùn)用到目錄中就會遇到問題酬屉,先看代碼:

    <Menu Margin="0,0,0,0" SnapsToDevicePixels="True" DataContext="{Binding Source={StaticResource Locator}, Path=MenuControl}">
        <MenuItem Header="Test  " ItemsSource="{Binding MenuItem}">
            <MenuItem.ItemTemplate>
                <DataTemplate>
                    <MenuItem Header="{Binding MenuItemText}" Command="{Binding MenuCommand}"/>
                </DataTemplate>
            </MenuItem.ItemTemplate>
        </MenuItem>
    </Menu>

按照我們上次說的半等,這個代碼已經(jīng)完美的完成了綁定,的確他可以很好的顯示動態(tài)數(shù)據(jù)的內(nèi)容呐萨,但是你會發(fā)現(xiàn)指令并不會被執(zhí)行杀饵。因為在MenuItem處已經(jīng)指定了ItemsSource的內(nèi)容,下面所有的綁定內(nèi)容都會從ItemsSource綁定的集合中尋找谬擦,所以Header能夠直接綁定元素名稱切距,但是內(nèi)部并沒有MenuCommand這個東西。在這里需要用到RelativeSource的內(nèi)容惨远,先貼代碼:

            <MenuItem Header="Test" ItemsSource="{Binding MenuItem}">
                <MenuItem.ItemContainerStyle>
                    <Style TargetType="{x:Type MenuItem}">
                        <Setter Property="Command"
                                Value="{Binding DataContext.MenuCommand,
                                                RelativeSource={RelativeSource AncestorType={x:Type MenuItem},
                                                Mode=FindAncestor, AncestorLevel=1}}"/>
                    </Style>
                </MenuItem.ItemContainerStyle>
            </MenuItem>

用RelativeSource尋找Item的祖先谜悟,把對象定義為Menu中的一個MenuItem话肖,然后綁定到這個資源的DataContext.MenuCommand就行了,其實是很簡單的問題葡幸,主要看書最筒。
引以為戒。

歡迎指正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蔚叨,一起剝皮案震驚了整個濱河市床蜘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蔑水,老刑警劉巖邢锯,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異搀别,居然都是意外死亡丹擎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門歇父,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸥鹉,“玉大人,你說我怎么就攤上這事庶骄』偕” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵单刁,是天一觀的道長灸异。 經(jīng)常有香客問我,道長羔飞,這世上最難降的妖魔是什么肺樟? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮逻淌,結(jié)果婚禮上么伯,老公的妹妹穿的比我還像新娘。我一直安慰自己卡儒,他們只是感情好田柔,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骨望,像睡著了一般硬爆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上擎鸠,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天缀磕,我揣著相機(jī)與錄音,去河邊找鬼。 笑死袜蚕,一個胖子當(dāng)著我的面吹牛糟把,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牲剃,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼遣疯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了颠黎?” 一聲冷哼從身側(cè)響起另锋,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤滞项,失蹤者是張志新(化名)和其女友劉穎狭归,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體文判,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡过椎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了戏仓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疚宇。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖赏殃,靈堂內(nèi)的尸體忽然破棺而出敷待,到底是詐尸還是另有隱情,我是刑警寧澤仁热,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布榜揖,位于F島的核電站,受9級特大地震影響抗蠢,放射性物質(zhì)發(fā)生泄漏举哟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一迅矛、第九天 我趴在偏房一處隱蔽的房頂上張望妨猩。 院中可真熱鬧,春花似錦秽褒、人聲如沸壶硅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽森瘪。三九已至,卻和暖如春票堵,著一層夾襖步出監(jiān)牢的瞬間扼睬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留窗宇,地道東北人措伐。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像军俊,于是被迫代替她去往敵國和親侥加。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容