我確定我在這裏錯過了一些非常愚蠢和愚蠢的事情,當我看到它時可能會踢自己,但我只是有一個簡單的問題。從ViewModel訪問MVVM設計模式中的this.content
我有在後臺代碼與網格視圖的構造函數中的一些代碼,即執行以下操作:
Grid mainGrid = this.Content as Grid;
MenuItem item = mainGrid.ContextMenu.Items[0] as MenuItem;
this.ApplySkinFromMenuItem(item);
所以我的問題是我怎麼能做到這一點從視圖模型? ViewModel不知道「this」是什麼,也沒有對「this」的引用。
這是我的理解是,視圖模型對象在XAML創建致電:
<ObjectDataProvider x:Key="TimersHostViewModel" ObjectType="{x:Type local:TimersHostViewModel}"/>
和設置像這樣的數據上下文:
<Grid DataContext="{StaticResource TimersHostViewModel}" Style="{DynamicResource styleBackground}">
但是,這並沒有給TimersHostViewModel關於「this.Content」的任何知識,並說TimersHost.Content沒有幫助,因爲TimersHost不是一個實際的對象,而是一個類,我需要一個實際的對象來獲得「.Content」,它應該是正確的對象,是來自代碼背後的對象,但我怎麼能那麼進入視圖模型?
畢竟以下的MVVM意味着ViewModel不應該有任何關於View的知識,View不應該有任何關於ViewModel的知識,而且他們只是通過綁定和INotifyPropertyChanged和其他類似的消息來回傳遞傳球技術。我在另一個應用程序中完成了一些這樣的工作,所以我對某些基本知識很熟悉,但仍然是一些新知識,仍然在學習甚至重新學習。
我已經在下面列出了全部內容。正如你所看到的,我正在試圖將代碼從代碼中移出並放到ViewModel中,但是當我試圖從主網格獲取this.Content時遇到了編譯器錯誤。
XAML:
<Window
x:Class="TimersXP.TimersHost"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:local="clr-namespace:TimersXP"
Name="TimersHostView"
SizeToContent="Height"
Title="TimersXP"
WindowStartupLocation="CenterScreen"
WindowStyle="ToolWindow">
<Window.Resources>
<ObjectDataProvider x:Key="TimersHostViewModel" ObjectType="{x:Type local:TimersHostViewModel}"/>
</Window.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="21"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="90"/>
</Grid.ColumnDefinitions>
<!--Main Menu-->
<Menu IsMainMenu="True" Style="{DynamicResource styleBanner}" Margin="0,0,0,1">
<MenuItem Header="_Help" Style="{DynamicResource styleBanner}">
<MenuItem Header="_About" Style="{DynamicResource styleBanner}"/>
</MenuItem>
</Menu>
<!--Top Most Check Box-->
<CheckBox Content="Top Most" Grid.Column="1" Height="16" HorizontalAlignment="Left" Margin="11,2,0,0" Name="checkBox1" VerticalAlignment="Top" />
<!--Stopwatch & Countdown Tab Defintions-->
<TabControl Grid.Row="1" Grid.ColumnSpan="2" Style="{DynamicResource styleContentArea}">
<TabItem Header="Stopwatch"/>
<TabItem Header="Countdown"/>
</TabControl>
<!-- CONTEXT MENU -->
<Grid.ContextMenu>
<ContextMenu Style="{DynamicResource styleBanner}" MenuItem.Click="OnMenuItemClick">
<MenuItem Tag=".\Resources\Skins\BlackSkin.xaml" IsChecked="True">
<MenuItem.Header>
<Rectangle Width="120" Height="40" Fill="Black" />
</MenuItem.Header>
</MenuItem>
<MenuItem Tag=".\Resources\Skins\GreenSkin.xaml">
<MenuItem.Header>
<Rectangle Width="120" Height="40" Fill="Green" />
</MenuItem.Header>
</MenuItem>
<MenuItem Tag=".\Resources\Skins\BlueSkin.xaml">
<MenuItem.Header>
<Rectangle Width="120" Height="40" Fill="Blue" />
</MenuItem.Header>
</MenuItem>
</ContextMenu>
</Grid.ContextMenu>
</Grid>
</Window>
代碼背後:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
namespace TimersXP
{
public partial class TimersHost : Window
{
public TimersHost()
{
try
{
InitializeComponent();
}
catch (Exception ex)
{
Debug.WriteLine("CTOR Exception: " + ex.Message);
}
// Load the default skin.
Grid mainGrid = this.Content as Grid;
MenuItem item = mainGrid.ContextMenu.Items[0] as MenuItem;
this.ApplySkinFromMenuItem(item);
}
public void OnMenuItemClick(object sender, RoutedEventArgs e)
{
MenuItem item = e.OriginalSource as MenuItem;
// Update the checked state of the menu items.
//Grid mainGrid = this.Content as Grid;
//foreach (MenuItem mi in mainGrid.ContextMenu.Items)
//mi.IsChecked = mi == item;
// Load the selected skin.
this.ApplySkinFromMenuItem(item);
}
void ApplySkinFromMenuItem(MenuItem item)
{
// Get a relative path to the ResourceDictionary which
// contains the selected skin.
string skinDictPath = item.Tag as string;
Uri skinDictUri = new Uri(skinDictPath, UriKind.Relative);
// Tell the Application to load the skin resources.
App app = Application.Current as App;
app.ApplySkin(skinDictUri);
}
}
}
視圖模型:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
namespace TimersXP
{
public class TimersHostViewModel
{
public TimersHostViewModel()
{
// Load the default skin.
Grid mainGrid = this.Content as Grid; <---- ERROR HERE
}
//public void TimersHostViewModel()
//{
// // Load the default skin.
// Grid mainGrid = TimersHost.Content as Grid;
// MenuItem item = mainGrid.ContextMenu.Items[0] as MenuItem;
// //this.ApplySkinFromMenuItem(item);
//}
public void OnMenuItemClick(object sender, RoutedEventArgs e)
{
MenuItem item = e.OriginalSource as MenuItem;
// Update the checked state of the menu items.
//Grid mainGrid = this.Content as Grid;
//foreach (MenuItem mi in mainGrid.ContextMenu.Items)
// mi.IsChecked = mi == item;
// Load the selected skin.
this.ApplySkinFromMenuItem(item);
}
void ApplySkinFromMenuItem(MenuItem item)
{
// Get a relative path to the ResourceDictionary which contains the selected skin.
string skinDictPath = item.Tag as string;
Uri skinDictUri = new Uri(skinDictPath, UriKind.Relative);
// Tell the Application to load the skin resources.
App app = Application.Current as App;
app.ApplySkin(skinDictUri);
}
}
}
好吧,我明白你要去哪裏。你的建議指向一種完全的設計方式,所以我甚至不需要這個。作爲Grid的內容。我完美地理解你的意思,這很有道理。我以前做過這個,不知道爲什麼我沒有想到它。感謝您的正確方向。我沒有把這個問題作爲解決方案進行投票,但是我會盡可能地做到這一點。再次感謝! –
很高興幫助。祝你好運。 –