2012-02-28 31 views
12

構建具有自定義「高對比度」主題的應用程序,用於戶外使用,可在運行期間打開和關閉。這是通過合併和取消合併包含類似下面的樣式資源字典罰款...基於風格的DynamicResourceOn

<Style x:Key="{x:Type MenuItem}" TargetType="{x:Type MenuItem}"> 
    <Setter Property="OverridesDefaultStyle" Value="true"/> 
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/> 
    <Setter Property="Template" Value="{StaticResource Theme_MenuItemTemplate}"/> 
</Style> 

這當一個菜單項的使用不指定樣式的偉大工程。這對於許多情況來說並不現實,因爲沒有方式來綁定沒有樣式的ItemsSource生成的子項。例如:

<ContextMenu.ItemContainerStyle> 
    <Style TargetType="MenuItem"> 
     <Setter Property="Header" Value="{Binding Path=Name}"/> 
     <Setter Property="IsCheckable" Value="True"/> 
     <Setter Property="IsChecked" Value="{Binding Path=Checked}"/> 
     <EventSetter Event="Checked" Handler="HistoryItem_Checked"/> 
    </Style> 
</ContextMenu.ItemContainerStyle> 

每隔後在計算器上說,你只需要做到這一點...

<Style TargetType="MenuItem" BasedOn="{StaticResource {x:Type MenuItem}}"> 
    <!-- Your overrides --> 
</Style> 

但是,這並不對我的情況下工作,因爲我的支持算法FMP能夠而且將會在運行時改變(當然,你不能在BasedOn屬性上使用DynamicResource擴展)。在我的應用程序中執行此操作時,會導致控件在控件加載時覆蓋其樣式,而每個其他控件在沒有重新加載的情況下正確切換時會導致控件被阻塞。

所以我的問題......

有沒有辦法讓DynamicResource擴展支持算法FMP工作或有另一種方法/幫閒我可以實現得到這個工作?

回答

7

終於想通了一個DynamicResouceStyle.BasedOn使用AttachedDependencyProperty的解決方案。

這裏是ItemsControl.ItemContainerStyle修復(可以很容易地修改,以改變FrameworkElement.Style

public class DynamicContainerStyle 
{ 
    public static Style GetBaseStyle(DependencyObject obj) 
    { 
     return (Style)obj.GetValue(BaseStyleProperty); 
    } 

    public static void SetBaseStyle(DependencyObject obj, Style value) 
    { 
     obj.SetValue(BaseStyleProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for BaseStyle. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty BaseStyleProperty = 
     DependencyProperty.RegisterAttached("BaseStyle", typeof(Style), typeof(DynamicContainerStyle), new UIPropertyMetadata(DynamicContainerStyle.StylesChanged)); 

    public static Style GetDerivedStyle(DependencyObject obj) 
    { 
     return (Style)obj.GetValue(DerivedStyleProperty); 
    } 

    public static void SetDerivedStyle(DependencyObject obj, Style value) 
    { 
     obj.SetValue(DerivedStyleProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for DerivedStyle. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty DerivedStyleProperty = 
     DependencyProperty.RegisterAttached("DerivedStyle", typeof(Style), typeof(DynamicContainerStyle), new UIPropertyMetadata(DynamicContainerStyle.StylesChanged)); 

    private static void StylesChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
    { 
     if (!typeof(System.Windows.Controls.ItemsControl).IsAssignableFrom(target.GetType())) 
      throw new InvalidCastException("Target must be ItemsControl"); 

     var Element = (System.Windows.Controls.ItemsControl)target; 

     var Styles = new List<Style>(); 

     var BaseStyle = GetBaseStyle(target); 

     if (BaseStyle != null) 
      Styles.Add(BaseStyle); 

     var DerivedStyle = GetDerivedStyle(target); 

     if (DerivedStyle != null) 
      Styles.Add(DerivedStyle); 

     Element.ItemContainerStyle = MergeStyles(Styles); 
    } 

    private static Style MergeStyles(ICollection<Style> Styles) 
    { 
     var NewStyle = new Style(); 

     foreach (var Style in Styles) 
     { 
      foreach (var Setter in Style.Setters) 
       NewStyle.Setters.Add(Setter); 

      foreach (var Trigger in Style.Triggers) 
       NewStyle.Triggers.Add(Trigger); 
     } 

     return NewStyle; 
    } 
} 

而且這裏有一個例子...

<!-- xmlns:ap points to the namespace where DynamicContainerStyle class lives --> 
<MenuItem Header="Recent" 
    ItemsSource="{Binding Path=RecentFiles}" 
    IsEnabled="{Binding RelativeSource={RelativeSource Self}, Path=HasItems}" 
    ap:DynamicContainerStyle.BaseStyle="{DynamicResource {x:Type MenuItem}}"> 
    <ap:DynamicContainerStyle.DerivedStyle> 
     <Style TargetType="MenuItem"> 
      <EventSetter Event="Click" Handler="RecentFile_Clicked"/> 
     </Style> 
    </ap:DynamicContainerStyle.DerivedStyle> 
    <MenuItem.ItemTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding}"/> 
     </DataTemplate> 
    </MenuItem.ItemTemplate> 
</MenuItem> 

下面是修改後的版本,設置了FrameworkElement.Style而不是在我回答另一篇文章: Setting a local implicit style different from theme-style/alternative to BasedOn DynamicResource

+0

有一種更簡單的方法來「複製」基本樣式。我在一個新的答案中添加了這個。 – aliceraunsbaek 2013-11-15 13:18:34

1

您的樣式應該位於UIElement.Resources標記中。這可以動態清除並重新填充。

我做同樣的事情,但沒有複雜的是這樣的:

MobileApp.Get().Resources.MergedDictionaries.Clear(); 

Uri uri = new Uri("/Resources/DayModeButton.xaml", UriKind.Relative); 
ResourceDictionary resDict = Application.LoadComponent(uri) as ResourceDictionary; 

resDict["SelectedColor"] = selectedColor; //change an attribute of resdict 

MobileApp.Get().Resources.MergedDictionaries.Add(resDict); 
+0

這幾乎是我爲合併和取消合併資源字典所做的。我不確定你的意思是由UIElement.Resoruces標籤。 – NtscCobalt 2012-02-28 23:08:29

+0

我測試過將樣式放置在UIElement.Resources中,而不是在中明確地設置樣式,但它具有相同的效果,我發現使用更易於閱讀。 – NtscCobalt 2012-02-28 23:16:51

3

我有一個微小的imp對於NtscCobalts的回答:

#region Type-specific function (FrameworkElement) 
    private static void StylesChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
    { 
     var mergedStyles = GetMergedStyles<FrameworkElement>(target, GetBaseStyle(target), GetDerivedStyle(target)); // NOTE: change type on copy 

     var element = (FrameworkElement)target; // NOTE: change type on copy 

     element.Style = mergedStyles; 
    } 
    #endregion Type-specific function (FrameworkElement) 


    #region Reused-function 
    public static Style GetMergedStyles<T>(DependencyObject target, Style baseStyle, Style derivedStyle) where T : DependencyObject 
    { 
     if (!(target is T)) throw new InvalidCastException("Target must be " + typeof(T)); 

     if (derivedStyle == null) return baseStyle; 
     if (baseStyle == null) return derivedStyle; 

     var newStyle = new Style { BasedOn = baseStyle, TargetType = derivedStyle.TargetType }; 
     foreach (var setter in derivedStyle.Setters) newStyle.Setters.Add(setter); 
     foreach (var trigger in derivedStyle.Triggers) newStyle.Triggers.Add(trigger); 
     return newStyle; 

    } 
    #endregion Reused-function 

您會發現,創建新樣式時可以簡單地設置基礎樣式。這樣,基本樣式中的基本樣式自動處於層次結構中。