【问题标题】:How to add style in Xaml for a Window created from code with mvvm?如何在 Xaml 中为使用 mvvm 的代码创建的窗口添加样式?
【发布时间】:2015-09-03 15:05:17
【问题描述】:

这个问题参考了这个链接Opening new window in MVVM WPF

如果我有以下情况:

public class WindowService:IWindowService {
     public void ShowWindow(object viewModel){
         var win = new Window {Content = viewModel};
         win.Show();
     }
}

还有我的 app.xaml 代码:

<DataTemplate DataType="{x:Type local:MyViewModel}">
        <local:MyUserControlView  />
</DataTemplate>

我不想在代码中添加如下样式:

 public class WindowService:IWindowService {
     public void ShowWindow(object viewModel){
         var win = new Window {Content = viewModel};
         win.SizeToContent = SizeToContent.WidthAndHeight;
         win.ResizeMode = ResizeMode.NoResize;
         win.WindowStartupLocation = WindowStartupLocation.CenterScreen;
         win.Icon =...
         win.Show();
     }
}

有没有办法在 Xaml 中使用 dataTemplate 做到这一点?

我想要一种方法来更改在 WindowService 中创建的窗口的样式,而不是在代码中。不是全局样式,但如果我有 viewModel1 和 viewModel2 showWindow 将能够根据传递给它的 viewModel 创建两个具有不同样式的窗口

【问题讨论】:

    标签: c# wpf xaml mvvm


    【解决方案1】:

    要实现这一点,您可以使用 Windows ContentTemplateSelector 属性。首先创建一个新的 DataTemplateSelector 类。此类的目的是根据您传入的 ViewModel 的类型来识别要使用的数据模板。在 SelectTemplate 方法中,有一个参数对象项。在那里,您可以获得窗口的内容,在您的情况下,在您拥有的服务中,您将视图模型传递给窗口的内容。因此,您将能够从该对象参数中获取视图模型。

     public class WindowTemplateSelector : DataTemplateSelector
      {
        public DataTemplate ViewModelTemplate1 { get; set; }
        public DataTemplate ViewModelTemplate2 { get; set; }
    
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
          if (item is ViewModel1)
            return ViewModelTemplate1;
          else
            return ViewModelTemplate2;
        }
      }
    

    然后在 Application.Resources 中添加两个数据模板和一个模板选择器的实例。您可以看到,在local:WindowTemplateSelector 中,我们为ViewModelTemplate1ViewModelTemplate2 指定了哪个数据模板。

    <Application x:Class="WpfApplication1.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:local="clr-namespace:WpfApplication1"
                 StartupUri="MainWindow.xaml">
      <Application.Resources>
        <DataTemplate x:Key="Template1">
          <Grid>
            <TextBlock Text="Hello World" />
          </Grid>
        </DataTemplate>
        <DataTemplate x:Key="Template2">
          <Grid>
            <TextBox Text="Hello World" />
          </Grid>
        </DataTemplate>
        <local:WindowTemplateSelector x:Key="windowTemplateSelector" 
                                      ViewModelTemplate1="{StaticResource Template1}"
                                      ViewModelTemplate2="{StaticResource Template2}"/>
      </Application.Resources>
    </Application>
    

    然后你需要将模板选择器传递给服务。

    public class WindowService:IWindowService {
         public void ShowWindow(object viewModel, DataTemplateSelector templateSelector){
             var win = new Window {Content = viewModel};
             win.ContentTemplateSelector = templateSelector;
             win.Show();
         }
    }
    

    有了这个,您可以为窗口的不同视图模型创建多个模板。

    【讨论】:

    • 我想通过代码创建一个窗口而不指定其类型(在您的示例中为 Window2),这就是我使用 DataTemplate 的原因。
    • 好的,感谢您的更新,现在有没有一种方法我不需要在 WindowService 中设置样式?我希望这个类是通用的,如果我将另一个需要不同样式的 viewModel 传递给它,它将以与识别视图时相同的方式识别样式(我没有在这里手动设置用户控件)。不知道我的问题是否清楚?
    • 您希望窗口具有您定义的全局样式吗?所以每次你展示一个窗口,它都会给你同样的风格?
    • 我想要一种能够在 xaml 中而不是在代码中更改在 WindowService 中创建的窗口样式的方法。不是全局样式,但如果例如我有 viewModel1 和 viewModel2 showWindow 将能够根据传递给它的 viewModel 创建两个具有不同样式的窗口
    • 哦,我明白了,你试过窗口的 ContentTemplateSelector 属性了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-16
    • 2010-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    相关资源
    最近更新 更多