2016-02-05 58 views
0

我在想,是否可以將某些控件的樣式與WPF中的自定義窗口關聯起來。只在一個自定義窗口中自動繼承控件樣式

這裏是場景 - 我創建了一個自定義窗口,併爲我將在此窗口中使用的許多控件定義了樣式。這些包含在可移植的類庫中。

捕捉的是我只有希望控件在自定義窗口(應用程序中有幾個不同的窗口)中使用樣式。

我明白,我可以指定樣式的按鍵,並使用包語法從我在我的應用程序的App.xaml移植的庫加載它們,例如:

<Application.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
      <ResourceDictionary Source="pack://application:,,,/Custom.Application.Library.Controls;component/Styles/CheckBox.xaml"/> 
     </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</Application.Resources> 

然後中添加和樣式的控制我的自定義窗口,例如:

<CheckBox x:Name="checkBox" Style="{StaticResource SpecialCheckBox}" 

但我真的很想做的是確定他們在我的類庫的風格,沒有一個密鑰,如本:

<Style TargetType="{x:Type CheckBox}"> 

取而代之的是:

<Style x:Key="SpecialCheckBox" TargetType="{x:Type CheckBox}"> 

這樣當此複選框在我的自定義窗口用它自動繼承的風格。如果我像這樣定義樣式,並將其加載到我的app.xaml中,問題顯而易見,所有複選框都將繼承此樣式,而不僅僅是我自定義窗口中使用的複選框。

所以,我試圖找到的是,如果有任何方式顯式地將樣式資源與自定義窗口關聯,以便我可以定義沒有密鑰的樣式,並且默認情況下繼承「特殊「風格,當在我的自定義窗口中使用時,但在應用程序的任何其他窗口中使用WPF默認值。有人對此有經驗嗎?

爲了清楚起見,這裏是我的自定義窗口的代碼:

XAML:

<!-- Window style --> 
<Style TargetType="{x:Type Controls:CCTApplicationWindow}"> 
    <Setter Property="WindowStyle" Value="None"/> 
    <Setter Property="AllowsTransparency" Value="True"/> 
    <Setter Property="ResizeMode" Value="CanResizeWithGrip"/> 
    <Setter Property="MinWidth" Value="500"/> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type Controls:CCTApplicationWindow}"> 
       <Border BorderBrush="#FF999999"> 
        <Border.Style> 
         <Style TargetType="{x:Type Border}"> 
          <Setter Property="BorderThickness" Value="1"/> 
          <Style.Triggers> 
           <DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=WindowState}" Value="Maximized"> 
            <Setter Property="BorderThickness" Value="7"/> 
           </DataTrigger> 
          </Style.Triggers> 
         </Style> 
        </Border.Style> 
        <Grid> 
         <Grid> 
          <Grid.RowDefinitions> 
           <RowDefinition Height="29"/> 
           <RowDefinition /> 
          </Grid.RowDefinitions> 
          <Controls:CCTApplicationHeader Grid.Row="0" 
                  Margin="0" 
                  Title="{TemplateBinding Title}" 
                  DragMoveCommand="{TemplateBinding DragMoveCommand}" 
                  MaximizeCommand="{TemplateBinding MaximizeCommand}" 
                  MinimizeCommand="{TemplateBinding MinimizeCommand}" 
                  CloseCommand="{TemplateBinding CloseCommand}"/> 
          <Grid Background="White" Grid.Row="1" Margin="0"> 
           <AdornerDecorator> 
            <ContentPresenter/> 
           </AdornerDecorator> 
          </Grid> 
         </Grid> 
        </Grid> 
       </Border> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

CS:

public partial class CCTApplicationWindow : Window 
{ 
    public static readonly DependencyProperty MaximizeCommandProperty = DependencyProperty.Register("MaximizeCommand", typeof(DelegateCommand), typeof(CCTApplicationWindow)); 
    public static readonly DependencyProperty MinimizeCommandProperty = DependencyProperty.Register("MinimizeCommand", typeof(DelegateCommand), typeof(CCTApplicationWindow)); 
    public static readonly DependencyProperty CloseCommandProperty = DependencyProperty.Register("CloseCommand", typeof(DelegateCommand), typeof(CCTApplicationWindow)); 
    public static readonly DependencyProperty DragMoveCommandProperty = DependencyProperty.Register("DragMoveCommand", typeof(DelegateCommand), typeof(CCTApplicationWindow)); 

    public CCTApplicationWindow() 
    { 
     MaximizeCommand = new DelegateCommand(MaximizeExecute); 
     MinimizeCommand = new DelegateCommand(MinimizeExecute); 
     CloseCommand = new DelegateCommand(CloseExecute); 
     DragMoveCommand = new DelegateCommand(DragMoveExecute); 
    } 

    static CCTApplicationWindow() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(CCTApplicationWindow), new FrameworkPropertyMetadata(typeof(CCTApplicationWindow))); 
    } 

    public DelegateCommand MaximizeCommand 
    { 
     get 
     { 
      return (DelegateCommand)GetValue(MaximizeCommandProperty); 
     } 
     set 
     { 
      SetValue(MaximizeCommandProperty, value); 
     } 
    } 

    public DelegateCommand MinimizeCommand 
    { 
     get 
     { 
      return (DelegateCommand)GetValue(MinimizeCommandProperty); 
     } 
     set 
     { 
      SetValue(MinimizeCommandProperty, value); 
     } 
    } 

    public DelegateCommand CloseCommand 
    { 
     get 
     { 
      return (DelegateCommand)GetValue(CloseCommandProperty); 
     } 
     set 
     { 
      SetValue(CloseCommandProperty, value); 
     } 
    } 

    public DelegateCommand DragMoveCommand 
    { 
     get 
     { 
      return (DelegateCommand)GetValue(DragMoveCommandProperty); 
     } 
     set 
     { 
      SetValue(DragMoveCommandProperty, value); 
     } 
    } 

    private void MaximizeExecute(object obj) 
    { 
     if (this.WindowState != WindowState.Maximized) 
     { 
      this.WindowState = WindowState.Maximized; 
     } 
     else 
     { 
      SystemCommands.RestoreWindow(this); 
     } 
    } 

    private void MinimizeExecute(object obj) 
    { 
     SystemCommands.MinimizeWindow(this); 
    } 

    private void CloseExecute(object obj) 
    { 
     SystemCommands.CloseWindow(this); 
    } 

    private void DragMoveExecute(object obj) 
    { 
     DragMove(); 
    } 
} 

回答

0

是的,你可以做到這一點,但你不應該!您已將此問題標記爲MVVM,但您的架構設計完全打破了MVVM。 MVVM的重點在於視圖模型層包含視圖邏輯;你的視圖模型是應該跟蹤邏輯層次結構的視圖模型,它們是應該將屬性暴露給視圖以控制其外觀的視圖模型。換句話說,就是因爲XAML足夠靈活並且足夠強大以實現這樣的邏輯並不意味着它是實際實現它的最佳場所!

要回答你的問題,是的,這可以通過與ObjectToTypeConverter綁定到父級的DataTrigger來完成。下面是設置TextBlock的背景矢菊花的例子,除非其母公司爲在這種情況下,應設置爲淡金黃網格:

<StackPanel Orientation="Vertical"> 

    <StackPanel.Resources> 
     <converters:ObjectToTypeConverter x:Key="ObjectToTypeConverter" /> 
     <Style TargetType="{x:Type TextBlock}"> 
      <Setter Property="Background" Value="CornflowerBlue" /> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding Path=Parent, RelativeSource={RelativeSource Mode=Self}, Converter={StaticResource ObjectToTypeConverter}}" Value="{x:Type Grid}"> 
        <Setter Property="Background" Value="PaleGoldenrod" /> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </StackPanel.Resources> 

    <Grid Width="100" Height="32" HorizontalAlignment="Left"> 
     <TextBlock Text="TextBox A" /> <!-- Gets a PaleGoldenrod background --> 
    </Grid> 
    <Canvas Width="100" Height="32" HorizontalAlignment="Left"> 
     <TextBlock Text="TextBox B" /> <!-- Gets a CornflowerBlue background --> 
    </Canvas> 

</StackPanel> 

而這裏的轉換器代碼。值得指出的是,如果你很樂意簡單地檢查一個給定類型的父對象是否存在於層次結構的某個地方(而不是直接父對象),那麼你甚至不需要這個,你可以嘗試綁定到RelativeSource將AncestorType設置爲相關的父類型。

// based on http://stackoverflow.com/questions/8244658/binding-to-the-object-gettype 
[ValueConversion(typeof(object), typeof(Type))] 
public class ObjectToTypeConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return value == null ? null : value.GetType(); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new InvalidOperationException(); 
    } 
} 

但同樣,我懇求你,如果你真的要堅持MVVM然後做不喜歡這樣!這正是MVVM旨在解決的「正確」問題。

0

最簡單的方法是爲您的Custom窗口創建單獨的ResourceDictionary。並使用它或者使用XAML或使用Code加載它。